1
/**********************************************************************
6
Created 11/29/1995 Heikki Tuuri
7
***********************************************************************/
17
#include "sync0sync.h"
22
#include "page0types.h"
23
#include "ibuf0ibuf.h"
26
#include "dict0boot.h"
31
#define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header
34
/* The data structures in files are defined just as byte strings in C */
35
typedef byte fsp_header_t;
41
File space header data structure: this data structure is contained in the
42
first page of a space. The space for this header is reserved in every extent
43
descriptor page, but used only in the first. */
45
/*-------------------------------------*/
46
#define FSP_SPACE_ID 0 /* space id */
47
#define FSP_NOT_USED 4 /* this field contained a value up to
48
which we know that the modifications
49
in the database have been flushed to
50
the file space; not used now */
51
#define FSP_SIZE 8 /* Current size of the space in
53
#define FSP_FREE_LIMIT 12 /* Minimum page number for which the
54
free list has not been initialized:
55
the pages >= this limit are, by
56
definition, free; note that in a
57
single-table tablespace where size
58
< 64 pages, this number is 64, i.e.,
59
we have initialized the space
60
about the first extent, but have not
61
physically allocted those pages to the
63
#define FSP_LOWEST_NO_WRITE 16 /* The lowest page offset for which
64
the page has not been written to disk
65
(if it has been written, we know that
66
the OS has really reserved the
67
physical space for the page) */
68
#define FSP_FRAG_N_USED 20 /* number of used pages in the
70
#define FSP_FREE 24 /* list of free extents */
71
#define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE)
72
/* list of partially free extents not
73
belonging to any segment */
74
#define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE)
75
/* list of full extents not belonging
77
#define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE)
78
/* 8 bytes which give the first unused
80
#define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE)
81
/* list of pages containing segment
82
headers, where all the segment inode
84
#define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE)
85
/* list of pages containing segment
86
headers, where not all the segment
87
header slots are reserved */
88
/*-------------------------------------*/
89
/* File space header size */
90
#define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE)
92
#define FSP_FREE_ADD 4 /* this many free extents are added
93
to the free list from above
94
FSP_FREE_LIMIT at a time */
99
Segment inode which is created for each segment in a tablespace. NOTE: in
100
purge we assume that a segment having only one currently used page can be
101
freed in a few steps, so that the freeing cannot fill the file buffer with
102
bufferfixed file pages. */
104
typedef byte fseg_inode_t;
106
#define FSEG_INODE_PAGE_NODE FSEG_PAGE_DATA
107
/* the list node for linking
108
segment inode pages */
110
#define FSEG_ARR_OFFSET (FSEG_PAGE_DATA + FLST_NODE_SIZE)
111
/*-------------------------------------*/
112
#define FSEG_ID 0 /* 8 bytes of segment id: if this is
113
ut_dulint_zero, it means that the
115
#define FSEG_NOT_FULL_N_USED 8
116
/* number of used segment pages in
117
the FSEG_NOT_FULL list */
119
/* list of free extents of this
121
#define FSEG_NOT_FULL (12 + FLST_BASE_NODE_SIZE)
122
/* list of partially free extents */
123
#define FSEG_FULL (12 + 2 * FLST_BASE_NODE_SIZE)
124
/* list of full extents */
125
#define FSEG_MAGIC_N (12 + 3 * FLST_BASE_NODE_SIZE)
126
/* magic number used in debugging */
127
#define FSEG_FRAG_ARR (16 + 3 * FLST_BASE_NODE_SIZE)
128
/* array of individual pages
129
belonging to this segment in fsp
130
fragment extent lists */
131
#define FSEG_FRAG_ARR_N_SLOTS (FSP_EXTENT_SIZE / 2)
132
/* number of slots in the array for
133
the fragment pages */
134
#define FSEG_FRAG_SLOT_SIZE 4 /* a fragment page slot contains its
135
page number within space, FIL_NULL
136
means that the slot is not in use */
137
/*-------------------------------------*/
138
#define FSEG_INODE_SIZE \
139
(16 + 3 * FLST_BASE_NODE_SIZE \
140
+ FSEG_FRAG_ARR_N_SLOTS * FSEG_FRAG_SLOT_SIZE)
142
#define FSP_SEG_INODES_PER_PAGE \
143
((UNIV_PAGE_SIZE - FSEG_ARR_OFFSET - 10) / FSEG_INODE_SIZE)
144
/* Number of segment inodes which fit on a
147
#define FSEG_MAGIC_N_VALUE 97937874
149
#define FSEG_FILLFACTOR 8 /* If this value is x, then if
150
the number of unused but reserved
151
pages in a segment is less than
152
reserved pages * 1/x, and there are
153
at least FSEG_FRAG_LIMIT used pages,
154
then we allow a new empty extent to
155
be added to the segment in
156
fseg_alloc_free_page. Otherwise, we
157
use unused pages of the segment. */
159
#define FSEG_FRAG_LIMIT FSEG_FRAG_ARR_N_SLOTS
160
/* If the segment has >= this many
161
used pages, it may be expanded by
162
allocating extents to the segment;
163
until that only individual fragment
164
pages are allocated from the space */
166
#define FSEG_FREE_LIST_LIMIT 40 /* If the reserved size of a segment
167
is at least this many extents, we
168
allow extents to be put to the free
169
list of the extent: at most
170
FSEG_FREE_LIST_MAX_LEN many */
171
#define FSEG_FREE_LIST_MAX_LEN 4
177
File extent descriptor data structure: contains bits to tell which pages in
178
the extent are free and which contain old tuple version to clean. */
180
/*-------------------------------------*/
181
#define XDES_ID 0 /* The identifier of the segment
182
to which this extent belongs */
183
#define XDES_FLST_NODE 8 /* The list node data structure
184
for the descriptors */
185
#define XDES_STATE (FLST_NODE_SIZE + 8)
186
/* contains state information
188
#define XDES_BITMAP (FLST_NODE_SIZE + 12)
189
/* Descriptor bitmap of the pages
191
/*-------------------------------------*/
193
#define XDES_BITS_PER_PAGE 2 /* How many bits are there per page */
194
#define XDES_FREE_BIT 0 /* Index of the bit which tells if
196
#define XDES_CLEAN_BIT 1 /* NOTE: currently not used!
197
Index of the bit which tells if
198
there are old versions of tuples
200
/* States of a descriptor */
201
#define XDES_FREE 1 /* extent is in free list of space */
202
#define XDES_FREE_FRAG 2 /* extent is in free fragment list of
204
#define XDES_FULL_FRAG 3 /* extent is in full fragment list of
206
#define XDES_FSEG 4 /* extent belongs to a segment */
208
/* File extent data structure size in bytes. */
210
(XDES_BITMAP + UT_BITS_IN_BYTES(FSP_EXTENT_SIZE * XDES_BITS_PER_PAGE))
212
/* Offset of the descriptor array on a descriptor page */
213
#define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE)
215
/**************************************************************************
216
Returns an extent to the free list of a space. */
221
ulint space, /* in: space id */
222
ulint page, /* in: page offset in the extent */
223
mtr_t* mtr); /* in: mtr */
224
/**************************************************************************
225
Frees an extent of a segment to the space free list. */
230
fseg_inode_t* seg_inode, /* in: segment inode */
231
ulint space, /* in: space id */
232
ulint page, /* in: page offset in the extent */
233
mtr_t* mtr); /* in: mtr handle */
234
/**************************************************************************
235
Calculates the number of pages reserved by a segment, and how
236
many pages are currently used. */
239
fseg_n_reserved_pages_low(
240
/*======================*/
241
/* out: number of reserved pages */
242
fseg_inode_t* header, /* in: segment inode */
243
ulint* used, /* out: number of pages used (<= reserved) */
244
mtr_t* mtr); /* in: mtr handle */
245
/************************************************************************
246
Marks a page used. The page must reside within the extents of the given
252
fseg_inode_t* seg_inode,/* in: segment inode */
253
ulint space, /* in: space id */
254
ulint page, /* in: page offset */
255
mtr_t* mtr); /* in: mtr */
256
/**************************************************************************
257
Returns the first extent descriptor for a segment. We think of the extent
258
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
262
fseg_get_first_extent(
263
/*==================*/
264
/* out: the first extent descriptor, or NULL if
266
fseg_inode_t* inode, /* in: segment inode */
267
mtr_t* mtr); /* in: mtr */
268
/**************************************************************************
269
Puts new extents to the free list if
270
there are free extents above the free limit. If an extent happens
271
to contain an extent descriptor page, the extent is put to
272
the FSP_FREE_FRAG list with the page marked as used. */
277
ibool init_space, /* in: TRUE if this is a single-table
278
tablespace and we are only initing
279
the tablespace's first extent
280
descriptor page and ibuf bitmap page;
281
then we do not allocate more extents */
282
ulint space, /* in: space */
283
fsp_header_t* header, /* in: space header */
284
mtr_t* mtr); /* in: mtr */
285
/**************************************************************************
286
Allocates a single free page from a segment. This function implements
287
the intelligent allocation strategy which tries to minimize file space
291
fseg_alloc_free_page_low(
292
/*=====================*/
293
/* out: the allocated page number, FIL_NULL
294
if no page could be allocated */
295
ulint space, /* in: space */
296
fseg_inode_t* seg_inode, /* in: segment inode */
297
ulint hint, /* in: hint of which page would be desirable */
298
byte direction, /* in: if the new page is needed because
299
of an index page split, and records are
300
inserted there in order, into which
301
direction they go alphabetically: FSP_DOWN,
302
FSP_UP, FSP_NO_DIR */
303
mtr_t* mtr); /* in: mtr handle */
306
/**************************************************************************
307
Reads the file space size stored in the header page. */
312
/* out: tablespace size stored in the space header */
313
page_t* page) /* in: header page (page 0 in the tablespace) */
315
return(mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SIZE));
318
/**************************************************************************
319
Gets a pointer to the space header and x-locks its page. */
322
fsp_get_space_header(
323
/*=================*/
324
/* out: pointer to the space header, page x-locked */
325
ulint id, /* in: space id */
326
mtr_t* mtr) /* in: mtr */
328
fsp_header_t* header;
332
header = FSP_HEADER_OFFSET + buf_page_get(id, 0, RW_X_LATCH, mtr);
333
#ifdef UNIV_SYNC_DEBUG
334
buf_page_dbg_add_level(header, SYNC_FSP_PAGE);
335
#endif /* UNIV_SYNC_DEBUG */
339
/**************************************************************************
340
Gets a descriptor bit of a page. */
345
/* out: TRUE if free */
346
xdes_t* descr, /* in: descriptor */
347
ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
348
ulint offset, /* in: page offset within extent:
349
0 ... FSP_EXTENT_SIZE - 1 */
350
mtr_t* mtr) /* in: mtr */
356
ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
357
MTR_MEMO_PAGE_X_FIX));
358
ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
359
ut_ad(offset < FSP_EXTENT_SIZE);
361
index = bit + XDES_BITS_PER_PAGE * offset;
363
byte_index = index / 8;
364
bit_index = index % 8;
366
return(ut_bit_get_nth(mtr_read_ulint(descr + XDES_BITMAP + byte_index,
371
/**************************************************************************
372
Sets a descriptor bit of a page. */
377
xdes_t* descr, /* in: descriptor */
378
ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
379
ulint offset, /* in: page offset within extent:
380
0 ... FSP_EXTENT_SIZE - 1 */
381
ibool val, /* in: bit value */
382
mtr_t* mtr) /* in: mtr */
389
ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
390
MTR_MEMO_PAGE_X_FIX));
391
ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
392
ut_ad(offset < FSP_EXTENT_SIZE);
394
index = bit + XDES_BITS_PER_PAGE * offset;
396
byte_index = index / 8;
397
bit_index = index % 8;
399
descr_byte = mtr_read_ulint(descr + XDES_BITMAP + byte_index,
401
descr_byte = ut_bit_set_nth(descr_byte, bit_index, val);
403
mlog_write_ulint(descr + XDES_BITMAP + byte_index, descr_byte,
407
/**************************************************************************
408
Looks for a descriptor bit having the desired value. Starts from hint
409
and scans upward; at the end of the extent the search is wrapped to
410
the start of the extent. */
415
/* out: bit index of the bit, ULINT_UNDEFINED if not
417
xdes_t* descr, /* in: descriptor */
418
ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
419
ibool val, /* in: desired bit value */
420
ulint hint, /* in: hint of which bit position would be desirable */
421
mtr_t* mtr) /* in: mtr */
427
ut_ad(hint < FSP_EXTENT_SIZE);
428
ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
429
MTR_MEMO_PAGE_X_FIX));
430
for (i = hint; i < FSP_EXTENT_SIZE; i++) {
431
if (val == xdes_get_bit(descr, bit, i, mtr)) {
437
for (i = 0; i < hint; i++) {
438
if (val == xdes_get_bit(descr, bit, i, mtr)) {
444
return(ULINT_UNDEFINED);
447
/**************************************************************************
448
Looks for a descriptor bit having the desired value. Scans the extent in
449
a direction opposite to xdes_find_bit. */
452
xdes_find_bit_downward(
453
/*===================*/
454
/* out: bit index of the bit, ULINT_UNDEFINED if not
456
xdes_t* descr, /* in: descriptor */
457
ulint bit, /* in: XDES_FREE_BIT or XDES_CLEAN_BIT */
458
ibool val, /* in: desired bit value */
459
ulint hint, /* in: hint of which bit position would be desirable */
460
mtr_t* mtr) /* in: mtr */
466
ut_ad(hint < FSP_EXTENT_SIZE);
467
ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
468
MTR_MEMO_PAGE_X_FIX));
469
for (i = hint + 1; i > 0; i--) {
470
if (val == xdes_get_bit(descr, bit, i - 1, mtr)) {
476
for (i = FSP_EXTENT_SIZE - 1; i > hint; i--) {
477
if (val == xdes_get_bit(descr, bit, i, mtr)) {
483
return(ULINT_UNDEFINED);
486
/**************************************************************************
487
Returns the number of used pages in a descriptor. */
492
/* out: number of pages used */
493
xdes_t* descr, /* in: descriptor */
494
mtr_t* mtr) /* in: mtr */
500
ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
501
MTR_MEMO_PAGE_X_FIX));
502
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
503
if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
511
/**************************************************************************
512
Returns true if extent contains no used pages. */
517
/* out: TRUE if totally free */
518
xdes_t* descr, /* in: descriptor */
519
mtr_t* mtr) /* in: mtr */
521
if (0 == xdes_get_n_used(descr, mtr)) {
529
/**************************************************************************
530
Returns true if extent contains no free pages. */
535
/* out: TRUE if full */
536
xdes_t* descr, /* in: descriptor */
537
mtr_t* mtr) /* in: mtr */
539
if (FSP_EXTENT_SIZE == xdes_get_n_used(descr, mtr)) {
547
/**************************************************************************
548
Sets the state of an xdes. */
553
xdes_t* descr, /* in: descriptor */
554
ulint state, /* in: state to set */
555
mtr_t* mtr) /* in: mtr handle */
558
ut_ad(state >= XDES_FREE);
559
ut_ad(state <= XDES_FSEG);
560
ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
561
MTR_MEMO_PAGE_X_FIX));
563
mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr);
566
/**************************************************************************
567
Gets the state of an xdes. */
573
xdes_t* descr, /* in: descriptor */
574
mtr_t* mtr) /* in: mtr handle */
577
ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
578
MTR_MEMO_PAGE_X_FIX));
580
return(mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr));
583
/**************************************************************************
584
Inits an extent descriptor to the free and clean state. */
589
xdes_t* descr, /* in: descriptor */
590
mtr_t* mtr) /* in: mtr */
595
ut_ad(mtr_memo_contains(mtr, buf_block_align(descr),
596
MTR_MEMO_PAGE_X_FIX));
597
ut_ad((XDES_SIZE - XDES_BITMAP) % 4 == 0);
599
for (i = XDES_BITMAP; i < XDES_SIZE; i += 4) {
600
mlog_write_ulint(descr + i, 0xFFFFFFFFUL, MLOG_4BYTES, mtr);
603
xdes_set_state(descr, XDES_FREE, mtr);
606
/************************************************************************
607
Calculates the page where the descriptor of a page resides. */
610
xdes_calc_descriptor_page(
611
/*======================*/
612
/* out: descriptor page offset */
613
ulint offset) /* in: page offset */
615
#if UNIV_PAGE_SIZE <= XDES_ARR_OFFSET \
616
+ (XDES_DESCRIBED_PER_PAGE / FSP_EXTENT_SIZE) * XDES_SIZE
620
return(ut_2pow_round(offset, XDES_DESCRIBED_PER_PAGE));
623
/************************************************************************
624
Calculates the descriptor index within a descriptor page. */
627
xdes_calc_descriptor_index(
628
/*=======================*/
629
/* out: descriptor index */
630
ulint offset) /* in: page offset */
632
return(ut_2pow_remainder(offset, XDES_DESCRIBED_PER_PAGE)
636
/************************************************************************
637
Gets pointer to a the extent descriptor of a page. The page where the extent
638
descriptor resides is x-locked. If the page offset is equal to the free limit
639
of the space, adds new extents from above the free limit to the space free
640
list, if not free limit == space size. This adding is necessary to make the
641
descriptor defined, as they are uninitialized above the free limit. */
644
xdes_get_descriptor_with_space_hdr(
645
/*===============================*/
646
/* out: pointer to the extent descriptor,
647
NULL if the page does not exist in the
648
space or if offset > free limit */
649
fsp_header_t* sp_header,/* in: space header, x-latched */
650
ulint space, /* in: space id */
651
ulint offset, /* in: page offset;
652
if equal to the free limit,
653
we try to add new extents to
654
the space free list */
655
mtr_t* mtr) /* in: mtr handle */
663
ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space),
665
/* Read free limit and space size */
666
limit = mtr_read_ulint(sp_header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
667
size = mtr_read_ulint(sp_header + FSP_SIZE, MLOG_4BYTES, mtr);
669
/* If offset is >= size or > limit, return NULL */
671
if ((offset >= size) || (offset > limit)) {
676
/* If offset is == limit, fill free list of the space. */
678
if (offset == limit) {
679
fsp_fill_free_list(FALSE, space, sp_header, mtr);
682
descr_page_no = xdes_calc_descriptor_page(offset);
684
if (descr_page_no == 0) {
685
/* It is on the space header page */
687
descr_page = buf_frame_align(sp_header);
689
descr_page = buf_page_get(space, descr_page_no, RW_X_LATCH,
691
#ifdef UNIV_SYNC_DEBUG
692
buf_page_dbg_add_level(descr_page, SYNC_FSP_PAGE);
693
#endif /* UNIV_SYNC_DEBUG */
696
return(descr_page + XDES_ARR_OFFSET
697
+ XDES_SIZE * xdes_calc_descriptor_index(offset));
700
/************************************************************************
701
Gets pointer to a the extent descriptor of a page. The page where the
702
extent descriptor resides is x-locked. If the page offset is equal to
703
the free limit of the space, adds new extents from above the free limit
704
to the space free list, if not free limit == space size. This adding
705
is necessary to make the descriptor defined, as they are uninitialized
706
above the free limit. */
711
/* out: pointer to the extent descriptor, NULL if the
712
page does not exist in the space or if offset > free
714
ulint space, /* in: space id */
715
ulint offset, /* in: page offset; if equal to the free limit,
716
we try to add new extents to the space free list */
717
mtr_t* mtr) /* in: mtr handle */
719
fsp_header_t* sp_header;
721
sp_header = FSP_HEADER_OFFSET
722
+ buf_page_get(space, 0, RW_X_LATCH, mtr);
723
#ifdef UNIV_SYNC_DEBUG
724
buf_page_dbg_add_level(sp_header, SYNC_FSP_PAGE);
725
#endif /* UNIV_SYNC_DEBUG */
726
return(xdes_get_descriptor_with_space_hdr(sp_header, space, offset,
730
/************************************************************************
731
Gets pointer to a the extent descriptor if the file address
732
of the descriptor list node is known. The page where the
733
extent descriptor resides is x-locked. */
736
xdes_lst_get_descriptor(
737
/*====================*/
738
/* out: pointer to the extent descriptor */
739
ulint space, /* in: space id */
740
fil_addr_t lst_node,/* in: file address of the list node
741
contained in the descriptor */
742
mtr_t* mtr) /* in: mtr handle */
747
ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space),
749
descr = fut_get_ptr(space, lst_node, RW_X_LATCH, mtr) - XDES_FLST_NODE;
754
/************************************************************************
755
Gets pointer to the next descriptor in a descriptor list and x-locks its
761
xdes_t* descr, /* in: pointer to a descriptor */
762
mtr_t* mtr) /* in: mtr handle */
768
space = buf_frame_get_space_id(descr);
770
return(xdes_lst_get_descriptor(
772
flst_get_next_addr(descr + XDES_FLST_NODE, mtr), mtr));
775
/************************************************************************
776
Returns page offset of the first page in extent described by a descriptor. */
781
/* out: offset of the first page in extent */
782
xdes_t* descr) /* in: extent descriptor */
786
return(buf_frame_get_page_no(descr)
787
+ ((descr - buf_frame_align(descr) - XDES_ARR_OFFSET)
792
/***************************************************************
793
Inits a file page whose prior contents should be ignored. */
796
fsp_init_file_page_low(
797
/*===================*/
798
byte* ptr) /* in: pointer to a page */
801
page = buf_frame_align(ptr);
803
buf_block_align(page)->check_index_page_at_flush = FALSE;
805
#ifdef UNIV_BASIC_LOG_DEBUG
806
memset(page, 0xff, UNIV_PAGE_SIZE);
808
mach_write_to_8(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM,
810
mach_write_to_8(page + FIL_PAGE_LSN, ut_dulint_zero);
813
/***************************************************************
814
Inits a file page whose prior contents should be ignored. */
819
page_t* page, /* in: page */
820
mtr_t* mtr) /* in: mtr */
822
fsp_init_file_page_low(page);
824
mlog_write_initial_log_record(page, MLOG_INIT_FILE_PAGE, mtr);
827
/***************************************************************
828
Parses a redo log record of a file page init. */
831
fsp_parse_init_file_page(
832
/*=====================*/
833
/* out: end of log record or NULL */
834
byte* ptr, /* in: buffer */
835
byte* end_ptr __attribute__((unused)), /* in: buffer end */
836
page_t* page) /* in: page or NULL */
838
ut_ad(ptr && end_ptr);
841
fsp_init_file_page_low(page);
847
/**************************************************************************
848
Initializes the fsp system. */
854
/* Does nothing at the moment */
857
/**************************************************************************
858
Writes the space id to a tablespace header. This function is used past the
859
buffer pool when we in fil0fil.c create a new single-table tablespace. */
862
fsp_header_write_space_id(
863
/*======================*/
864
page_t* page, /* in: first page in the space */
865
ulint space_id) /* in: space id */
867
mach_write_to_4(page + FSP_HEADER_OFFSET + FSP_SPACE_ID, space_id);
870
/**************************************************************************
871
Initializes the space header of a new created space and creates also the
872
insert buffer tree root if space == 0. */
877
ulint space, /* in: space id */
878
ulint size, /* in: current size in blocks */
879
mtr_t* mtr) /* in: mini-transaction handle */
881
fsp_header_t* header;
886
mtr_x_lock(fil_space_get_latch(space), mtr);
888
page = buf_page_create(space, 0, mtr);
889
buf_page_get(space, 0, RW_X_LATCH, mtr);
890
#ifdef UNIV_SYNC_DEBUG
891
buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
892
#endif /* UNIV_SYNC_DEBUG */
894
/* The prior contents of the file page should be ignored */
896
fsp_init_file_page(page, mtr);
898
mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_FSP_HDR,
901
header = FSP_HEADER_OFFSET + page;
903
mlog_write_ulint(header + FSP_SPACE_ID, space, MLOG_4BYTES, mtr);
904
mlog_write_ulint(header + FSP_NOT_USED, 0, MLOG_4BYTES, mtr);
906
mlog_write_ulint(header + FSP_SIZE, size, MLOG_4BYTES, mtr);
907
mlog_write_ulint(header + FSP_FREE_LIMIT, 0, MLOG_4BYTES, mtr);
908
mlog_write_ulint(header + FSP_LOWEST_NO_WRITE, 0, MLOG_4BYTES, mtr);
909
mlog_write_ulint(header + FSP_FRAG_N_USED, 0, MLOG_4BYTES, mtr);
911
flst_init(header + FSP_FREE, mtr);
912
flst_init(header + FSP_FREE_FRAG, mtr);
913
flst_init(header + FSP_FULL_FRAG, mtr);
914
flst_init(header + FSP_SEG_INODES_FULL, mtr);
915
flst_init(header + FSP_SEG_INODES_FREE, mtr);
917
mlog_write_dulint(header + FSP_SEG_ID, ut_dulint_create(0, 1), mtr);
919
fsp_fill_free_list(FALSE, space, header, mtr);
920
btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, space,
921
ut_dulint_add(DICT_IBUF_ID_MIN, space), FALSE, mtr);
923
fsp_fill_free_list(TRUE, space, header, mtr);
927
/**************************************************************************
928
Reads the space id from the first page of a tablespace. */
931
fsp_header_get_space_id(
932
/*====================*/
933
/* out: space id, ULINT UNDEFINED if error */
934
page_t* page) /* in: first page of a tablespace */
939
fsp_id = mach_read_from_4(FSP_HEADER_OFFSET + page + FSP_SPACE_ID);
941
id = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
945
"InnoDB: Error: space id in fsp header %lu,"
946
" but in the page header %lu\n",
947
(ulong) fsp_id, (ulong) id);
949
return(ULINT_UNDEFINED);
955
/**************************************************************************
956
Increases the space size field of a space. */
961
ulint space, /* in: space id */
962
ulint size_inc,/* in: size increment in pages */
963
mtr_t* mtr) /* in: mini-transaction handle */
965
fsp_header_t* header;
970
mtr_x_lock(fil_space_get_latch(space), mtr);
972
header = fsp_get_space_header(space, mtr);
974
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
976
mlog_write_ulint(header + FSP_SIZE, size + size_inc, MLOG_4BYTES,
980
/**************************************************************************
981
Gets the current free limit of a tablespace. The free limit means the
982
place of the first page which has never been put to the the free list
983
for allocation. The space above that address is initialized to zero.
984
Sets also the global variable log_fsp_current_free_limit. */
987
fsp_header_get_free_limit(
988
/*======================*/
989
/* out: free limit in megabytes */
990
ulint space) /* in: space id, must be 0 */
992
fsp_header_t* header;
996
ut_a(space == 0); /* We have only one log_fsp_current_... variable */
1000
mtr_x_lock(fil_space_get_latch(space), &mtr);
1002
header = fsp_get_space_header(space, &mtr);
1004
limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, &mtr);
1006
limit = limit / ((1024 * 1024) / UNIV_PAGE_SIZE);
1008
log_fsp_current_free_limit_set_and_checkpoint(limit);
1015
/**************************************************************************
1016
Gets the size of the tablespace from the tablespace header. If we do not
1017
have an auto-extending data file, this should be equal to the size of the
1018
data files. If there is an auto-extending data file, this can be smaller. */
1021
fsp_header_get_tablespace_size(
1022
/*===========================*/
1023
/* out: size in pages */
1024
ulint space) /* in: space id, must be 0 */
1026
fsp_header_t* header;
1030
ut_a(space == 0); /* We have only one log_fsp_current_... variable */
1034
mtr_x_lock(fil_space_get_latch(space), &mtr);
1036
header = fsp_get_space_header(space, &mtr);
1038
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
1045
/***************************************************************************
1046
Tries to extend a single-table tablespace so that a page would fit in the
1050
fsp_try_extend_data_file_with_pages(
1051
/*================================*/
1052
/* out: TRUE if success */
1053
ulint space, /* in: space */
1054
ulint page_no, /* in: page number */
1055
fsp_header_t* header, /* in: space header */
1056
mtr_t* mtr) /* in: mtr */
1064
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1066
ut_a(page_no >= size);
1068
success = fil_extend_space_to_desired_size(&actual_size, space,
1070
/* actual_size now has the space size in pages; it may be less than
1071
we wanted if we ran out of disk space */
1073
mlog_write_ulint(header + FSP_SIZE, actual_size, MLOG_4BYTES, mtr);
1078
/***************************************************************************
1079
Tries to extend the last data file of a tablespace if it is auto-extending. */
1082
fsp_try_extend_data_file(
1083
/*=====================*/
1084
/* out: FALSE if not auto-extending */
1085
ulint* actual_increase,/* out: actual increase in pages, where
1086
we measure the tablespace size from
1087
what the header field says; it may be
1088
the actual file size rounded down to
1090
ulint space, /* in: space */
1091
fsp_header_t* header, /* in: space header */
1092
mtr_t* mtr) /* in: mtr */
1097
ulint size_increase;
1101
*actual_increase = 0;
1103
if (space == 0 && !srv_auto_extend_last_data_file) {
1108
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1112
if (space == 0 && srv_last_file_size_max != 0) {
1113
if (srv_last_file_size_max
1114
< srv_data_file_sizes[srv_n_data_files - 1]) {
1117
"InnoDB: Error: Last data file size is %lu,"
1118
" max size allowed %lu\n",
1119
(ulong) srv_data_file_sizes[
1120
srv_n_data_files - 1],
1121
(ulong) srv_last_file_size_max);
1124
size_increase = srv_last_file_size_max
1125
- srv_data_file_sizes[srv_n_data_files - 1];
1126
if (size_increase > SRV_AUTO_EXTEND_INCREMENT) {
1127
size_increase = SRV_AUTO_EXTEND_INCREMENT;
1131
size_increase = SRV_AUTO_EXTEND_INCREMENT;
1133
/* We extend single-table tablespaces first one extent
1134
at a time, but for bigger tablespaces more. It is not
1135
enough to extend always by one extent, because some
1136
extents are frag page extents. */
1138
if (size < FSP_EXTENT_SIZE) {
1139
/* Let us first extend the file to 64 pages */
1140
success = fsp_try_extend_data_file_with_pages(
1141
space, FSP_EXTENT_SIZE - 1,
1144
new_size = mtr_read_ulint(
1148
*actual_increase = new_size - old_size;
1153
size = FSP_EXTENT_SIZE;
1156
if (size < 32 * FSP_EXTENT_SIZE) {
1157
size_increase = FSP_EXTENT_SIZE;
1159
/* Below in fsp_fill_free_list() we assume
1160
that we add at most FSP_FREE_ADD extents at
1162
size_increase = FSP_FREE_ADD * FSP_EXTENT_SIZE;
1167
if (size_increase == 0) {
1172
success = fil_extend_space_to_desired_size(&actual_size, space,
1173
size + size_increase);
1174
/* We ignore any fragments of a full megabyte when storing the size
1175
to the space header */
1177
mlog_write_ulint(header + FSP_SIZE,
1178
ut_calc_align_down(actual_size,
1179
(1024 * 1024) / UNIV_PAGE_SIZE),
1181
new_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1183
*actual_increase = new_size - old_size;
1188
/**************************************************************************
1189
Puts new extents to the free list if there are free extents above the free
1190
limit. If an extent happens to contain an extent descriptor page, the extent
1191
is put to the FSP_FREE_FRAG list with the page marked as used. */
1196
ibool init_space, /* in: TRUE if this is a single-table
1197
tablespace and we are only initing
1198
the tablespace's first extent
1199
descriptor page and ibuf bitmap page;
1200
then we do not allocate more extents */
1201
ulint space, /* in: space */
1202
fsp_header_t* header, /* in: space header */
1203
mtr_t* mtr) /* in: mtr */
1212
ulint actual_increase;
1216
ut_ad(header && mtr);
1218
/* Check if we can fill free list from above the free list limit */
1219
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1220
limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
1222
if (space == 0 && srv_auto_extend_last_data_file
1223
&& size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1225
/* Try to increase the last data file size */
1226
fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1227
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1230
if (space != 0 && !init_space
1231
&& size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1233
/* Try to increase the .ibd file size */
1234
fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1235
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1240
while ((init_space && i < 1)
1241
|| ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD))) {
1243
mlog_write_ulint(header + FSP_FREE_LIMIT, i + FSP_EXTENT_SIZE,
1246
/* Update the free limit info in the log system and make
1249
log_fsp_current_free_limit_set_and_checkpoint(
1250
(i + FSP_EXTENT_SIZE)
1251
/ ((1024 * 1024) / UNIV_PAGE_SIZE));
1254
if (0 == i % XDES_DESCRIBED_PER_PAGE) {
1256
/* We are going to initialize a new descriptor page
1257
and a new ibuf bitmap page: the prior contents of the
1258
pages should be ignored. */
1261
descr_page = buf_page_create(space, i, mtr);
1262
buf_page_get(space, i, RW_X_LATCH, mtr);
1263
#ifdef UNIV_SYNC_DEBUG
1264
buf_page_dbg_add_level(descr_page,
1266
#endif /* UNIV_SYNC_DEBUG */
1267
fsp_init_file_page(descr_page, mtr);
1268
mlog_write_ulint(descr_page + FIL_PAGE_TYPE,
1273
/* Initialize the ibuf bitmap page in a separate
1274
mini-transaction because it is low in the latching
1275
order, and we must be able to release its latch
1276
before returning from the fsp routine */
1278
mtr_start(&ibuf_mtr);
1280
ibuf_page = buf_page_create(space,
1281
i + FSP_IBUF_BITMAP_OFFSET,
1283
buf_page_get(space, i + FSP_IBUF_BITMAP_OFFSET,
1284
RW_X_LATCH, &ibuf_mtr);
1285
#ifdef UNIV_SYNC_DEBUG
1286
buf_page_dbg_add_level(ibuf_page, SYNC_FSP_PAGE);
1287
#endif /* UNIV_SYNC_DEBUG */
1288
fsp_init_file_page(ibuf_page, &ibuf_mtr);
1290
ibuf_bitmap_page_init(ibuf_page, &ibuf_mtr);
1292
mtr_commit(&ibuf_mtr);
1295
descr = xdes_get_descriptor_with_space_hdr(header, space, i,
1297
xdes_init(descr, mtr);
1299
#if XDES_DESCRIBED_PER_PAGE % FSP_EXTENT_SIZE
1300
# error "XDES_DESCRIBED_PER_PAGE % FSP_EXTENT_SIZE != 0"
1303
if (0 == i % XDES_DESCRIBED_PER_PAGE) {
1305
/* The first page in the extent is a descriptor page
1306
and the second is an ibuf bitmap page: mark them
1309
xdes_set_bit(descr, XDES_FREE_BIT, 0, FALSE, mtr);
1310
xdes_set_bit(descr, XDES_FREE_BIT,
1311
FSP_IBUF_BITMAP_OFFSET, FALSE, mtr);
1312
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1314
flst_add_last(header + FSP_FREE_FRAG,
1315
descr + XDES_FLST_NODE, mtr);
1316
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
1318
mlog_write_ulint(header + FSP_FRAG_N_USED,
1319
frag_n_used + 2, MLOG_4BYTES, mtr);
1321
flst_add_last(header + FSP_FREE,
1322
descr + XDES_FLST_NODE, mtr);
1326
i += FSP_EXTENT_SIZE;
1330
/**************************************************************************
1331
Allocates a new free extent. */
1334
fsp_alloc_free_extent(
1335
/*==================*/
1336
/* out: extent descriptor, NULL if cannot be
1338
ulint space, /* in: space id */
1339
ulint hint, /* in: hint of which extent would be desirable: any
1340
page offset in the extent goes; the hint must not
1341
be > FSP_FREE_LIMIT */
1342
mtr_t* mtr) /* in: mtr */
1344
fsp_header_t* header;
1350
header = fsp_get_space_header(space, mtr);
1352
descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1354
if (descr && (xdes_get_state(descr, mtr) == XDES_FREE)) {
1355
/* Ok, we can take this extent */
1357
/* Take the first extent in the free list */
1358
first = flst_get_first(header + FSP_FREE, mtr);
1360
if (fil_addr_is_null(first)) {
1361
fsp_fill_free_list(FALSE, space, header, mtr);
1363
first = flst_get_first(header + FSP_FREE, mtr);
1366
if (fil_addr_is_null(first)) {
1368
return(NULL); /* No free extents left */
1371
descr = xdes_lst_get_descriptor(space, first, mtr);
1374
flst_remove(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1379
/**************************************************************************
1380
Allocates a single free page from a space. The page is marked as used. */
1383
fsp_alloc_free_page(
1384
/*================*/
1385
/* out: the page offset, FIL_NULL if no page could
1387
ulint space, /* in: space id */
1388
ulint hint, /* in: hint of which page would be desirable */
1389
mtr_t* mtr) /* in: mtr handle */
1391
fsp_header_t* header;
1403
header = fsp_get_space_header(space, mtr);
1405
/* Get the hinted descriptor */
1406
descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1408
if (descr && (xdes_get_state(descr, mtr) == XDES_FREE_FRAG)) {
1409
/* Ok, we can take this extent */
1411
/* Else take the first extent in free_frag list */
1412
first = flst_get_first(header + FSP_FREE_FRAG, mtr);
1414
if (fil_addr_is_null(first)) {
1415
/* There are no partially full fragments: allocate
1416
a free extent and add it to the FREE_FRAG list. NOTE
1417
that the allocation may have as a side-effect that an
1418
extent containing a descriptor page is added to the
1419
FREE_FRAG list. But we will allocate our page from the
1420
the free extent anyway. */
1422
descr = fsp_alloc_free_extent(space, hint, mtr);
1424
if (descr == NULL) {
1425
/* No free space left */
1430
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1431
flst_add_last(header + FSP_FREE_FRAG,
1432
descr + XDES_FLST_NODE, mtr);
1434
descr = xdes_lst_get_descriptor(space, first, mtr);
1437
/* Reset the hint */
1441
/* Now we have in descr an extent with at least one free page. Look
1442
for a free page in the extent. */
1444
free = xdes_find_bit(descr, XDES_FREE_BIT, TRUE,
1445
hint % FSP_EXTENT_SIZE, mtr);
1446
if (free == ULINT_UNDEFINED) {
1448
ut_print_buf(stderr, ((byte*)descr) - 500, 1000);
1453
page_no = xdes_get_offset(descr) + free;
1455
space_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1457
if (space_size <= page_no) {
1458
/* It must be that we are extending a single-table tablespace
1459
whose size is still < 64 pages */
1462
if (page_no >= FSP_EXTENT_SIZE) {
1464
"InnoDB: Error: trying to extend a"
1465
" single-table tablespace %lu\n"
1466
"InnoDB: by single page(s) though the"
1467
" space size %lu. Page no %lu.\n",
1468
(ulong) space, (ulong) space_size,
1472
success = fsp_try_extend_data_file_with_pages(space, page_no,
1475
/* No disk space left */
1480
xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr);
1482
/* Update the FRAG_N_USED field */
1483
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1486
mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
1488
if (xdes_is_full(descr, mtr)) {
1489
/* The fragment is full: move it to another list */
1490
flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1492
xdes_set_state(descr, XDES_FULL_FRAG, mtr);
1494
flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1496
mlog_write_ulint(header + FSP_FRAG_N_USED,
1497
frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
1501
/* Initialize the allocated page to the buffer pool, so that it can
1502
be obtained immediately with buf_page_get without need for a disk
1505
buf_page_create(space, page_no, mtr);
1507
page = buf_page_get(space, page_no, RW_X_LATCH, mtr);
1508
#ifdef UNIV_SYNC_DEBUG
1509
buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
1510
#endif /* UNIV_SYNC_DEBUG */
1512
/* Prior contents of the page should be ignored */
1513
fsp_init_file_page(page, mtr);
1518
/**************************************************************************
1519
Frees a single page of a space. The page is marked as free and clean. */
1524
ulint space, /* in: space id */
1525
ulint page, /* in: page offset */
1526
mtr_t* mtr) /* in: mtr handle */
1528
fsp_header_t* header;
1535
/* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */
1537
header = fsp_get_space_header(space, mtr);
1539
descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1541
state = xdes_get_state(descr, mtr);
1543
if (state != XDES_FREE_FRAG && state != XDES_FULL_FRAG) {
1545
"InnoDB: Error: File space extent descriptor"
1546
" of page %lu has state %lu\n",
1549
fputs("InnoDB: Dump of descriptor: ", stderr);
1550
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1553
if (state == XDES_FREE) {
1554
/* We put here some fault tolerance: if the page
1555
is already free, return without doing anything! */
1563
if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
1565
"InnoDB: Error: File space extent descriptor"
1566
" of page %lu says it is free\n"
1567
"InnoDB: Dump of descriptor: ", (ulong) page);
1568
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1571
/* We put here some fault tolerance: if the page
1572
is already free, return without doing anything! */
1577
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1578
xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1580
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1582
if (state == XDES_FULL_FRAG) {
1583
/* The fragment was full: move it to another list */
1584
flst_remove(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1586
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1587
flst_add_last(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1589
mlog_write_ulint(header + FSP_FRAG_N_USED,
1590
frag_n_used + FSP_EXTENT_SIZE - 1,
1593
ut_a(frag_n_used > 0);
1594
mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used - 1,
1598
if (xdes_is_free(descr, mtr)) {
1599
/* The extent has become free: move it to another list */
1600
flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1602
fsp_free_extent(space, page, mtr);
1606
/**************************************************************************
1607
Returns an extent to the free list of a space. */
1612
ulint space, /* in: space id */
1613
ulint page, /* in: page offset in the extent */
1614
mtr_t* mtr) /* in: mtr */
1616
fsp_header_t* header;
1621
header = fsp_get_space_header(space, mtr);
1623
descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1625
if (xdes_get_state(descr, mtr) == XDES_FREE) {
1627
ut_print_buf(stderr, (byte*)descr - 500, 1000);
1632
xdes_init(descr, mtr);
1634
flst_add_last(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1637
/**************************************************************************
1638
Returns the nth inode slot on an inode page. */
1641
fsp_seg_inode_page_get_nth_inode(
1642
/*=============================*/
1643
/* out: segment inode */
1644
page_t* page, /* in: segment inode page */
1645
ulint i, /* in: inode index on page */
1646
mtr_t* mtr __attribute__((unused))) /* in: mini-transaction handle */
1648
ut_ad(i < FSP_SEG_INODES_PER_PAGE);
1649
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
1650
MTR_MEMO_PAGE_X_FIX));
1652
return(page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i);
1655
/**************************************************************************
1656
Looks for a used segment inode on a segment inode page. */
1659
fsp_seg_inode_page_find_used(
1660
/*=========================*/
1661
/* out: segment inode index, or ULINT_UNDEFINED
1663
page_t* page, /* in: segment inode page */
1664
mtr_t* mtr) /* in: mini-transaction handle */
1667
fseg_inode_t* inode;
1669
for (i = 0; i < FSP_SEG_INODES_PER_PAGE; i++) {
1671
inode = fsp_seg_inode_page_get_nth_inode(page, i, mtr);
1673
if (ut_dulint_cmp(mach_read_from_8(inode + FSEG_ID),
1674
ut_dulint_zero) != 0) {
1681
return(ULINT_UNDEFINED);
1684
/**************************************************************************
1685
Looks for an unused segment inode on a segment inode page. */
1688
fsp_seg_inode_page_find_free(
1689
/*=========================*/
1690
/* out: segment inode index, or ULINT_UNDEFINED
1692
page_t* page, /* in: segment inode page */
1693
ulint j, /* in: search forward starting from this index */
1694
mtr_t* mtr) /* in: mini-transaction handle */
1697
fseg_inode_t* inode;
1699
for (i = j; i < FSP_SEG_INODES_PER_PAGE; i++) {
1701
inode = fsp_seg_inode_page_get_nth_inode(page, i, mtr);
1703
if (ut_dulint_cmp(mach_read_from_8(inode + FSEG_ID),
1704
ut_dulint_zero) == 0) {
1705
/* This is unused */
1711
return(ULINT_UNDEFINED);
1714
/**************************************************************************
1715
Allocates a new file segment inode page. */
1718
fsp_alloc_seg_inode_page(
1719
/*=====================*/
1720
/* out: TRUE if could be allocated */
1721
fsp_header_t* space_header, /* in: space header */
1722
mtr_t* mtr) /* in: mini-transaction handle */
1724
fseg_inode_t* inode;
1730
space = buf_frame_get_space_id(space_header);
1732
page_no = fsp_alloc_free_page(space, 0, mtr);
1734
if (page_no == FIL_NULL) {
1739
page = buf_page_get(space, page_no, RW_X_LATCH, mtr);
1741
buf_block_align(page)->check_index_page_at_flush = FALSE;
1743
mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_INODE,
1745
#ifdef UNIV_SYNC_DEBUG
1746
buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
1747
#endif /* UNIV_SYNC_DEBUG */
1749
for (i = 0; i < FSP_SEG_INODES_PER_PAGE; i++) {
1751
inode = fsp_seg_inode_page_get_nth_inode(page, i, mtr);
1753
mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr);
1756
flst_add_last(space_header + FSP_SEG_INODES_FREE,
1757
page + FSEG_INODE_PAGE_NODE, mtr);
1761
/**************************************************************************
1762
Allocates a new file segment inode. */
1765
fsp_alloc_seg_inode(
1766
/*================*/
1767
/* out: segment inode, or NULL if
1769
fsp_header_t* space_header, /* in: space header */
1770
mtr_t* mtr) /* in: mini-transaction handle */
1774
fseg_inode_t* inode;
1778
if (flst_get_len(space_header + FSP_SEG_INODES_FREE, mtr) == 0) {
1779
/* Allocate a new segment inode page */
1781
success = fsp_alloc_seg_inode_page(space_header, mtr);
1789
page_no = flst_get_first(space_header + FSP_SEG_INODES_FREE, mtr).page;
1791
page = buf_page_get(buf_frame_get_space_id(space_header), page_no,
1793
#ifdef UNIV_SYNC_DEBUG
1794
buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
1795
#endif /* UNIV_SYNC_DEBUG */
1797
n = fsp_seg_inode_page_find_free(page, 0, mtr);
1799
ut_a(n != ULINT_UNDEFINED);
1801
inode = fsp_seg_inode_page_get_nth_inode(page, n, mtr);
1803
if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1,
1805
/* There are no other unused headers left on the page: move it
1808
flst_remove(space_header + FSP_SEG_INODES_FREE,
1809
page + FSEG_INODE_PAGE_NODE, mtr);
1811
flst_add_last(space_header + FSP_SEG_INODES_FULL,
1812
page + FSEG_INODE_PAGE_NODE, mtr);
1818
/**************************************************************************
1819
Frees a file segment inode. */
1824
ulint space, /* in: space id */
1825
fseg_inode_t* inode, /* in: segment inode */
1826
mtr_t* mtr) /* in: mini-transaction handle */
1829
fsp_header_t* space_header;
1831
page = buf_frame_align(inode);
1833
space_header = fsp_get_space_header(space, mtr);
1835
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
1837
if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, 0, mtr)) {
1839
/* Move the page to another list */
1841
flst_remove(space_header + FSP_SEG_INODES_FULL,
1842
page + FSEG_INODE_PAGE_NODE, mtr);
1844
flst_add_last(space_header + FSP_SEG_INODES_FREE,
1845
page + FSEG_INODE_PAGE_NODE, mtr);
1848
mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr);
1849
mlog_write_ulint(inode + FSEG_MAGIC_N, 0, MLOG_4BYTES, mtr);
1851
if (ULINT_UNDEFINED == fsp_seg_inode_page_find_used(page, mtr)) {
1853
/* There are no other used headers left on the page: free it */
1855
flst_remove(space_header + FSP_SEG_INODES_FREE,
1856
page + FSEG_INODE_PAGE_NODE, mtr);
1858
fsp_free_page(space, buf_frame_get_page_no(page), mtr);
1862
/**************************************************************************
1863
Returns the file segment inode, page x-latched. */
1868
/* out: segment inode, page x-latched */
1869
fseg_header_t* header, /* in: segment header */
1870
mtr_t* mtr) /* in: mtr handle */
1872
fil_addr_t inode_addr;
1873
fseg_inode_t* inode;
1875
inode_addr.page = mach_read_from_4(header + FSEG_HDR_PAGE_NO);
1876
inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET);
1878
inode = fut_get_ptr(mach_read_from_4(header + FSEG_HDR_SPACE),
1879
inode_addr, RW_X_LATCH, mtr);
1881
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
1886
/**************************************************************************
1887
Gets the page number from the nth fragment page slot. */
1890
fseg_get_nth_frag_page_no(
1891
/*======================*/
1892
/* out: page number, FIL_NULL if not in use */
1893
fseg_inode_t* inode, /* in: segment inode */
1894
ulint n, /* in: slot index */
1895
mtr_t* mtr __attribute__((unused))) /* in: mtr handle */
1897
ut_ad(inode && mtr);
1898
ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
1899
ut_ad(mtr_memo_contains(mtr, buf_block_align(inode),
1900
MTR_MEMO_PAGE_X_FIX));
1901
return(mach_read_from_4(inode + FSEG_FRAG_ARR
1902
+ n * FSEG_FRAG_SLOT_SIZE));
1905
/**************************************************************************
1906
Sets the page number in the nth fragment page slot. */
1909
fseg_set_nth_frag_page_no(
1910
/*======================*/
1911
fseg_inode_t* inode, /* in: segment inode */
1912
ulint n, /* in: slot index */
1913
ulint page_no,/* in: page number to set */
1914
mtr_t* mtr) /* in: mtr handle */
1916
ut_ad(inode && mtr);
1917
ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
1918
ut_ad(mtr_memo_contains(mtr, buf_block_align(inode),
1919
MTR_MEMO_PAGE_X_FIX));
1921
mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE,
1922
page_no, MLOG_4BYTES, mtr);
1925
/**************************************************************************
1926
Finds a fragment page slot which is free. */
1929
fseg_find_free_frag_page_slot(
1930
/*==========================*/
1931
/* out: slot index; ULINT_UNDEFINED if none
1933
fseg_inode_t* inode, /* in: segment inode */
1934
mtr_t* mtr) /* in: mtr handle */
1939
ut_ad(inode && mtr);
1941
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
1942
page_no = fseg_get_nth_frag_page_no(inode, i, mtr);
1944
if (page_no == FIL_NULL) {
1950
return(ULINT_UNDEFINED);
1953
/**************************************************************************
1954
Finds a fragment page slot which is used and last in the array. */
1957
fseg_find_last_used_frag_page_slot(
1958
/*===============================*/
1959
/* out: slot index; ULINT_UNDEFINED if none
1961
fseg_inode_t* inode, /* in: segment inode */
1962
mtr_t* mtr) /* in: mtr handle */
1967
ut_ad(inode && mtr);
1969
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
1970
page_no = fseg_get_nth_frag_page_no(
1971
inode, FSEG_FRAG_ARR_N_SLOTS - i - 1, mtr);
1973
if (page_no != FIL_NULL) {
1975
return(FSEG_FRAG_ARR_N_SLOTS - i - 1);
1979
return(ULINT_UNDEFINED);
1982
/**************************************************************************
1983
Calculates reserved fragment page slots. */
1986
fseg_get_n_frag_pages(
1987
/*==================*/
1988
/* out: number of fragment pages */
1989
fseg_inode_t* inode, /* in: segment inode */
1990
mtr_t* mtr) /* in: mtr handle */
1995
ut_ad(inode && mtr);
1997
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
1998
if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i, mtr)) {
2006
/**************************************************************************
2007
Creates a new segment. */
2010
fseg_create_general(
2011
/*================*/
2012
/* out: the page where the segment header is placed,
2013
x-latched, NULL if could not create segment
2014
because of lack of space */
2015
ulint space, /* in: space id */
2016
ulint page, /* in: page where the segment header is placed: if
2017
this is != 0, the page must belong to another segment,
2018
if this is 0, a new page will be allocated and it
2019
will belong to the created segment */
2020
ulint byte_offset, /* in: byte offset of the created segment header
2022
ibool has_done_reservation, /* in: TRUE if the caller has already
2023
done the reservation for the pages with
2024
fsp_reserve_free_extents (at least 2 extents: one for
2025
the inode and the other for the segment) then there is
2026
no need to do the check for this individual
2028
mtr_t* mtr) /* in: mtr */
2030
fsp_header_t* space_header;
2031
fseg_inode_t* inode;
2033
fseg_header_t* header = 0; /* remove warning */
2043
header = byte_offset + buf_page_get(space, page, RW_X_LATCH,
2047
ut_ad(!mutex_own(&kernel_mutex)
2048
|| mtr_memo_contains(mtr, fil_space_get_latch(space),
2050
latch = fil_space_get_latch(space);
2052
mtr_x_lock(latch, mtr);
2054
if (rw_lock_get_x_lock_count(latch) == 1) {
2055
/* This thread did not own the latch before this call: free
2056
excess pages from the insert buffer free list */
2059
ibuf_free_excess_pages(space);
2063
if (!has_done_reservation) {
2064
success = fsp_reserve_free_extents(&n_reserved, space, 2,
2071
space_header = fsp_get_space_header(space, mtr);
2073
inode = fsp_alloc_seg_inode(space_header, mtr);
2075
if (inode == NULL) {
2080
/* Read the next segment id from space header and increment the
2081
value in space header */
2083
seg_id = mtr_read_dulint(space_header + FSP_SEG_ID, mtr);
2085
mlog_write_dulint(space_header + FSP_SEG_ID, ut_dulint_add(seg_id, 1),
2088
mlog_write_dulint(inode + FSEG_ID, seg_id, mtr);
2089
mlog_write_ulint(inode + FSEG_NOT_FULL_N_USED, 0, MLOG_4BYTES, mtr);
2091
flst_init(inode + FSEG_FREE, mtr);
2092
flst_init(inode + FSEG_NOT_FULL, mtr);
2093
flst_init(inode + FSEG_FULL, mtr);
2095
mlog_write_ulint(inode + FSEG_MAGIC_N, FSEG_MAGIC_N_VALUE,
2097
for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2098
fseg_set_nth_frag_page_no(inode, i, FIL_NULL, mtr);
2102
page = fseg_alloc_free_page_low(space, inode, 0, FSP_UP, mtr);
2104
if (page == FIL_NULL) {
2106
fsp_free_seg_inode(space, inode, mtr);
2111
header = byte_offset
2112
+ buf_page_get(space, page, RW_X_LATCH, mtr);
2113
mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE,
2114
FIL_PAGE_TYPE_SYS, MLOG_2BYTES, mtr);
2117
mlog_write_ulint(header + FSEG_HDR_OFFSET,
2118
inode - buf_frame_align(inode), MLOG_2BYTES, mtr);
2120
mlog_write_ulint(header + FSEG_HDR_PAGE_NO,
2121
buf_frame_get_page_no(inode), MLOG_4BYTES, mtr);
2123
mlog_write_ulint(header + FSEG_HDR_SPACE, space, MLOG_4BYTES, mtr);
2125
ret = buf_frame_align(header);
2128
if (!has_done_reservation) {
2130
fil_space_release_free_extents(space, n_reserved);
2136
/**************************************************************************
2137
Creates a new segment. */
2142
/* out: the page where the segment header is placed,
2143
x-latched, NULL if could not create segment
2144
because of lack of space */
2145
ulint space, /* in: space id */
2146
ulint page, /* in: page where the segment header is placed: if
2147
this is != 0, the page must belong to another segment,
2148
if this is 0, a new page will be allocated and it
2149
will belong to the created segment */
2150
ulint byte_offset, /* in: byte offset of the created segment header
2152
mtr_t* mtr) /* in: mtr */
2154
return(fseg_create_general(space, page, byte_offset, FALSE, mtr));
2157
/**************************************************************************
2158
Calculates the number of pages reserved by a segment, and how many pages are
2162
fseg_n_reserved_pages_low(
2163
/*======================*/
2164
/* out: number of reserved pages */
2165
fseg_inode_t* inode, /* in: segment inode */
2166
ulint* used, /* out: number of pages used (<= reserved) */
2167
mtr_t* mtr) /* in: mtr handle */
2171
ut_ad(inode && used && mtr);
2172
ut_ad(mtr_memo_contains(mtr, buf_block_align(inode),
2173
MTR_MEMO_PAGE_X_FIX));
2175
*used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr)
2176
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr)
2177
+ fseg_get_n_frag_pages(inode, mtr);
2179
ret = fseg_get_n_frag_pages(inode, mtr)
2180
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FREE, mtr)
2181
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_NOT_FULL, mtr)
2182
+ FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr);
2187
/**************************************************************************
2188
Calculates the number of pages reserved by a segment, and how many pages are
2192
fseg_n_reserved_pages(
2193
/*==================*/
2194
/* out: number of reserved pages */
2195
fseg_header_t* header, /* in: segment header */
2196
ulint* used, /* out: number of pages used (<= reserved) */
2197
mtr_t* mtr) /* in: mtr handle */
2200
fseg_inode_t* inode;
2203
space = buf_frame_get_space_id(header);
2205
ut_ad(!mutex_own(&kernel_mutex)
2206
|| mtr_memo_contains(mtr, fil_space_get_latch(space),
2209
mtr_x_lock(fil_space_get_latch(space), mtr);
2211
inode = fseg_inode_get(header, mtr);
2213
ret = fseg_n_reserved_pages_low(inode, used, mtr);
2218
/*************************************************************************
2219
Tries to fill the free list of a segment with consecutive free extents.
2220
This happens if the segment is big enough to allow extents in the free list,
2221
the free list is empty, and the extents can be allocated consecutively from
2225
fseg_fill_free_list(
2226
/*================*/
2227
fseg_inode_t* inode, /* in: segment inode */
2228
ulint space, /* in: space id */
2229
ulint hint, /* in: hint which extent would be good as
2231
mtr_t* mtr) /* in: mtr */
2239
ut_ad(inode && mtr);
2241
reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
2243
if (reserved < FSEG_FREE_LIST_LIMIT * FSP_EXTENT_SIZE) {
2245
/* The segment is too small to allow extents in free list */
2250
if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2251
/* Free list is not empty */
2256
for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) {
2257
descr = xdes_get_descriptor(space, hint, mtr);
2260
|| (XDES_FREE != xdes_get_state(descr, mtr))) {
2262
/* We cannot allocate the desired extent: stop */
2267
descr = fsp_alloc_free_extent(space, hint, mtr);
2269
xdes_set_state(descr, XDES_FSEG, mtr);
2271
seg_id = mtr_read_dulint(inode + FSEG_ID, mtr);
2272
mlog_write_dulint(descr + XDES_ID, seg_id, mtr);
2274
flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2275
hint += FSP_EXTENT_SIZE;
2279
/*************************************************************************
2280
Allocates a free extent for the segment: looks first in the free list of the
2281
segment, then tries to allocate from the space free list. NOTE that the extent
2282
returned still resides in the segment free list, it is not yet taken off it! */
2285
fseg_alloc_free_extent(
2286
/*===================*/
2287
/* out: allocated extent, still placed in the
2288
segment free list, NULL if could
2290
fseg_inode_t* inode, /* in: segment inode */
2291
ulint space, /* in: space id */
2292
mtr_t* mtr) /* in: mtr */
2298
if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2299
/* Segment free list is not empty, allocate from it */
2301
first = flst_get_first(inode + FSEG_FREE, mtr);
2303
descr = xdes_lst_get_descriptor(space, first, mtr);
2305
/* Segment free list was empty, allocate from space */
2306
descr = fsp_alloc_free_extent(space, 0, mtr);
2308
if (descr == NULL) {
2313
seg_id = mtr_read_dulint(inode + FSEG_ID, mtr);
2315
xdes_set_state(descr, XDES_FSEG, mtr);
2316
mlog_write_dulint(descr + XDES_ID, seg_id, mtr);
2317
flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2319
/* Try to fill the segment free list */
2320
fseg_fill_free_list(inode, space,
2321
xdes_get_offset(descr) + FSP_EXTENT_SIZE,
2328
/**************************************************************************
2329
Allocates a single free page from a segment. This function implements
2330
the intelligent allocation strategy which tries to minimize file space
2334
fseg_alloc_free_page_low(
2335
/*=====================*/
2336
/* out: the allocated page number, FIL_NULL
2337
if no page could be allocated */
2338
ulint space, /* in: space */
2339
fseg_inode_t* seg_inode, /* in: segment inode */
2340
ulint hint, /* in: hint of which page would be desirable */
2341
byte direction, /* in: if the new page is needed because
2342
of an index page split, and records are
2343
inserted there in order, into which
2344
direction they go alphabetically: FSP_DOWN,
2345
FSP_UP, FSP_NO_DIR */
2346
mtr_t* mtr) /* in: mtr handle */
2348
fsp_header_t* space_header;
2353
xdes_t* descr; /* extent of the hinted page */
2354
ulint ret_page; /* the allocated page offset, FIL_NULL
2355
if could not be allocated */
2356
xdes_t* ret_descr; /* the extent of the allocated page */
2358
ibool frag_page_allocated = FALSE;
2363
ut_ad((direction >= FSP_UP) && (direction <= FSP_NO_DIR));
2364
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
2365
== FSEG_MAGIC_N_VALUE);
2366
seg_id = mtr_read_dulint(seg_inode + FSEG_ID, mtr);
2368
ut_ad(ut_dulint_cmp(seg_id, ut_dulint_zero) > 0);
2370
reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr);
2372
space_header = fsp_get_space_header(space, mtr);
2374
descr = xdes_get_descriptor_with_space_hdr(space_header, space,
2376
if (descr == NULL) {
2377
/* Hint outside space or too high above free limit: reset
2380
descr = xdes_get_descriptor(space, hint, mtr);
2383
/* In the big if-else below we look for ret_page and ret_descr */
2384
/*-------------------------------------------------------------*/
2385
if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2386
&& (0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID,
2388
&& (xdes_get_bit(descr, XDES_FREE_BIT,
2389
hint % FSP_EXTENT_SIZE, mtr) == TRUE)) {
2391
/* 1. We can take the hinted page
2392
=================================*/
2395
/*-----------------------------------------------------------*/
2396
} else if ((xdes_get_state(descr, mtr) == XDES_FREE)
2397
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
2398
&& (used >= FSEG_FRAG_LIMIT)) {
2400
/* 2. We allocate the free extent from space and can take
2401
=========================================================
2404
ret_descr = fsp_alloc_free_extent(space, hint, mtr);
2406
ut_a(ret_descr == descr);
2408
xdes_set_state(ret_descr, XDES_FSEG, mtr);
2409
mlog_write_dulint(ret_descr + XDES_ID, seg_id, mtr);
2410
flst_add_last(seg_inode + FSEG_FREE,
2411
ret_descr + XDES_FLST_NODE, mtr);
2413
/* Try to fill the segment free list */
2414
fseg_fill_free_list(seg_inode, space,
2415
hint + FSP_EXTENT_SIZE, mtr);
2417
/*-----------------------------------------------------------*/
2418
} else if ((direction != FSP_NO_DIR)
2419
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
2420
&& (used >= FSEG_FRAG_LIMIT)
2422
= fseg_alloc_free_extent(seg_inode, space, mtr)))) {
2424
/* 3. We take any free extent (which was already assigned above
2425
===============================================================
2426
in the if-condition to ret_descr) and take the lowest or
2427
========================================================
2428
highest page in it, depending on the direction
2429
==============================================*/
2430
ret_page = xdes_get_offset(ret_descr);
2432
if (direction == FSP_DOWN) {
2433
ret_page += FSP_EXTENT_SIZE - 1;
2435
/*-----------------------------------------------------------*/
2436
} else if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2437
&& (0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID,
2439
&& (!xdes_is_full(descr, mtr))) {
2441
/* 4. We can take the page from the same extent as the
2442
======================================================
2443
hinted page (and the extent already belongs to the
2444
==================================================
2448
ret_page = xdes_get_offset(ret_descr)
2449
+ xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2450
hint % FSP_EXTENT_SIZE, mtr);
2451
/*-----------------------------------------------------------*/
2452
} else if (reserved - used > 0) {
2453
/* 5. We take any unused page from the segment
2454
==============================================*/
2457
if (flst_get_len(seg_inode + FSEG_NOT_FULL, mtr) > 0) {
2458
first = flst_get_first(seg_inode + FSEG_NOT_FULL,
2460
} else if (flst_get_len(seg_inode + FSEG_FREE, mtr) > 0) {
2461
first = flst_get_first(seg_inode + FSEG_FREE, mtr);
2467
ret_descr = xdes_lst_get_descriptor(space, first, mtr);
2468
ret_page = xdes_get_offset(ret_descr)
2469
+ xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2471
/*-----------------------------------------------------------*/
2472
} else if (used < FSEG_FRAG_LIMIT) {
2473
/* 6. We allocate an individual page from the space
2474
===================================================*/
2475
ret_page = fsp_alloc_free_page(space, hint, mtr);
2478
frag_page_allocated = TRUE;
2480
if (ret_page != FIL_NULL) {
2481
/* Put the page in the fragment page array of the
2483
n = fseg_find_free_frag_page_slot(seg_inode, mtr);
2484
ut_a(n != FIL_NULL);
2486
fseg_set_nth_frag_page_no(seg_inode, n, ret_page,
2489
/*-----------------------------------------------------------*/
2491
/* 7. We allocate a new extent and take its first page
2492
======================================================*/
2493
ret_descr = fseg_alloc_free_extent(seg_inode, space, mtr);
2495
if (ret_descr == NULL) {
2496
ret_page = FIL_NULL;
2498
ret_page = xdes_get_offset(ret_descr);
2502
if (ret_page == FIL_NULL) {
2503
/* Page could not be allocated */
2509
space_size = fil_space_get_size(space);
2511
if (space_size <= ret_page) {
2512
/* It must be that we are extending a single-table
2513
tablespace whose size is still < 64 pages */
2515
if (ret_page >= FSP_EXTENT_SIZE) {
2517
"InnoDB: Error (2): trying to extend"
2518
" a single-table tablespace %lu\n"
2519
"InnoDB: by single page(s) though"
2520
" the space size %lu. Page no %lu.\n",
2521
(ulong) space, (ulong) space_size,
2526
success = fsp_try_extend_data_file_with_pages(
2527
space, ret_page, space_header, mtr);
2529
/* No disk space left */
2535
if (!frag_page_allocated) {
2536
/* Initialize the allocated page to buffer pool, so that it
2537
can be obtained immediately with buf_page_get without need
2540
page = buf_page_create(space, ret_page, mtr);
2542
ut_a(page == buf_page_get(space, ret_page, RW_X_LATCH, mtr));
2544
#ifdef UNIV_SYNC_DEBUG
2545
buf_page_dbg_add_level(page, SYNC_FSP_PAGE);
2546
#endif /* UNIV_SYNC_DEBUG */
2548
/* The prior contents of the page should be ignored */
2549
fsp_init_file_page(page, mtr);
2551
/* At this point we know the extent and the page offset.
2552
The extent is still in the appropriate list (FSEG_NOT_FULL
2553
or FSEG_FREE), and the page is not yet marked as used. */
2555
ut_ad(xdes_get_descriptor(space, ret_page, mtr) == ret_descr);
2556
ut_ad(xdes_get_bit(ret_descr, XDES_FREE_BIT,
2557
ret_page % FSP_EXTENT_SIZE, mtr) == TRUE);
2559
fseg_mark_page_used(seg_inode, space, ret_page, mtr);
2562
buf_reset_check_index_page_at_flush(space, ret_page);
2567
/**************************************************************************
2568
Allocates a single free page from a segment. This function implements
2569
the intelligent allocation strategy which tries to minimize file space
2573
fseg_alloc_free_page_general(
2574
/*=========================*/
2575
/* out: allocated page offset, FIL_NULL if no
2576
page could be allocated */
2577
fseg_header_t* seg_header,/* in: segment header */
2578
ulint hint, /* in: hint of which page would be desirable */
2579
byte direction,/* in: if the new page is needed because
2580
of an index page split, and records are
2581
inserted there in order, into which
2582
direction they go alphabetically: FSP_DOWN,
2583
FSP_UP, FSP_NO_DIR */
2584
ibool has_done_reservation, /* in: TRUE if the caller has
2585
already done the reservation for the page
2586
with fsp_reserve_free_extents, then there
2587
is no need to do the check for this individual
2589
mtr_t* mtr) /* in: mtr handle */
2591
fseg_inode_t* inode;
2598
space = buf_frame_get_space_id(seg_header);
2600
ut_ad(!mutex_own(&kernel_mutex)
2601
|| mtr_memo_contains(mtr, fil_space_get_latch(space),
2603
latch = fil_space_get_latch(space);
2605
mtr_x_lock(latch, mtr);
2607
if (rw_lock_get_x_lock_count(latch) == 1) {
2608
/* This thread did not own the latch before this call: free
2609
excess pages from the insert buffer free list */
2612
ibuf_free_excess_pages(space);
2616
inode = fseg_inode_get(seg_header, mtr);
2618
if (!has_done_reservation) {
2619
success = fsp_reserve_free_extents(&n_reserved, space, 2,
2626
page_no = fseg_alloc_free_page_low(buf_frame_get_space_id(inode),
2627
inode, hint, direction, mtr);
2628
if (!has_done_reservation) {
2629
fil_space_release_free_extents(space, n_reserved);
2635
/**************************************************************************
2636
Allocates a single free page from a segment. This function implements
2637
the intelligent allocation strategy which tries to minimize file space
2641
fseg_alloc_free_page(
2642
/*=================*/
2643
/* out: allocated page offset, FIL_NULL if no
2644
page could be allocated */
2645
fseg_header_t* seg_header,/* in: segment header */
2646
ulint hint, /* in: hint of which page would be desirable */
2647
byte direction,/* in: if the new page is needed because
2648
of an index page split, and records are
2649
inserted there in order, into which
2650
direction they go alphabetically: FSP_DOWN,
2651
FSP_UP, FSP_NO_DIR */
2652
mtr_t* mtr) /* in: mtr handle */
2654
return(fseg_alloc_free_page_general(seg_header, hint, direction,
2658
/**************************************************************************
2659
Checks that we have at least 2 frag pages free in the first extent of a
2660
single-table tablespace, and they are also physically initialized to the data
2661
file. That is we have already extended the data file so that those pages are
2662
inside the data file. If not, this function extends the tablespace with
2666
fsp_reserve_free_pages(
2667
/*===================*/
2668
/* out: TRUE if there were >= 3 free
2669
pages, or we were able to extend */
2670
ulint space, /* in: space id, must be != 0 */
2671
fsp_header_t* space_header, /* in: header of that space,
2673
ulint size, /* in: size of the tablespace in pages,
2674
must be < FSP_EXTENT_SIZE / 2 */
2675
mtr_t* mtr) /* in: mtr */
2681
ut_a(size < FSP_EXTENT_SIZE / 2);
2683
descr = xdes_get_descriptor_with_space_hdr(space_header, space, 0,
2685
n_used = xdes_get_n_used(descr, mtr);
2687
ut_a(n_used <= size);
2689
if (size >= n_used + 2) {
2694
return(fsp_try_extend_data_file_with_pages(space, n_used + 1,
2695
space_header, mtr));
2698
/**************************************************************************
2699
Reserves free pages from a tablespace. All mini-transactions which may
2700
use several pages from the tablespace should call this function beforehand
2701
and reserve enough free extents so that they certainly will be able
2702
to do their operation, like a B-tree page split, fully. Reservations
2703
must be released with function fil_space_release_free_extents!
2705
The alloc_type below has the following meaning: FSP_NORMAL means an
2706
operation which will probably result in more space usage, like an
2707
insert in a B-tree; FSP_UNDO means allocation to undo logs: if we are
2708
deleting rows, then this allocation will in the long run result in
2709
less space usage (after a purge); FSP_CLEANING means allocation done
2710
in a physical record delete (like in a purge) or other cleaning operation
2711
which will result in less space usage in the long run. We prefer the latter
2712
two types of allocation: when space is scarce, FSP_NORMAL allocations
2713
will not succeed, but the latter two allocations will succeed, if possible.
2714
The purpose is to avoid dead end where the database is full but the
2715
user cannot free any space because these freeing operations temporarily
2718
Single-table tablespaces whose size is < 32 pages are a special case. In this
2719
function we would liberally reserve several 64 page extents for every page
2720
split or merge in a B-tree. But we do not want to waste disk space if the table
2721
only occupies < 32 pages. That is why we apply different rules in that special
2722
case, just ensuring that there are 3 free pages available. */
2725
fsp_reserve_free_extents(
2726
/*=====================*/
2727
/* out: TRUE if we were able to make the reservation */
2728
ulint* n_reserved,/* out: number of extents actually reserved; if we
2729
return TRUE and the tablespace size is < 64 pages,
2730
then this can be 0, otherwise it is n_ext */
2731
ulint space, /* in: space id */
2732
ulint n_ext, /* in: number of extents to reserve */
2733
ulint alloc_type,/* in: FSP_NORMAL, FSP_UNDO, or FSP_CLEANING */
2734
mtr_t* mtr) /* in: mtr */
2736
fsp_header_t* space_header;
2738
ulint n_free_list_ext;
2745
ulint n_pages_added;
2748
ut_ad(!mutex_own(&kernel_mutex)
2749
|| mtr_memo_contains(mtr, fil_space_get_latch(space),
2751
*n_reserved = n_ext;
2753
latch = fil_space_get_latch(space);
2755
mtr_x_lock(latch, mtr);
2757
space_header = fsp_get_space_header(space, mtr);
2759
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr);
2761
if (size < FSP_EXTENT_SIZE / 2) {
2762
/* Use different rules for small single-table tablespaces */
2764
return(fsp_reserve_free_pages(space, space_header, size, mtr));
2767
n_free_list_ext = flst_get_len(space_header + FSP_FREE, mtr);
2769
free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
2772
/* Below we play safe when counting free extents above the free limit:
2773
some of them will contain extent descriptor pages, and therefore
2774
will not be free extents */
2776
n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
2778
if (n_free_up > 0) {
2780
n_free_up = n_free_up - n_free_up
2781
/ (XDES_DESCRIBED_PER_PAGE / FSP_EXTENT_SIZE);
2784
n_free = n_free_list_ext + n_free_up;
2786
if (alloc_type == FSP_NORMAL) {
2787
/* We reserve 1 extent + 0.5 % of the space size to undo logs
2788
and 1 extent + 0.5 % to cleaning operations; NOTE: this source
2789
code is duplicated in the function below! */
2791
reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
2793
if (n_free <= reserve + n_ext) {
2797
} else if (alloc_type == FSP_UNDO) {
2798
/* We reserve 0.5 % of the space size to cleaning operations */
2800
reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 200;
2802
if (n_free <= reserve + n_ext) {
2807
ut_a(alloc_type == FSP_CLEANING);
2810
success = fil_space_reserve_free_extents(space, n_free, n_ext);
2816
success = fsp_try_extend_data_file(&n_pages_added, space,
2818
if (success && n_pages_added > 0) {
2826
/**************************************************************************
2827
This function should be used to get information on how much we still
2828
will be able to insert new data to the database without running out the
2829
tablespace. Only free extents are taken into account and we also subtract
2830
the safety margin required by the above function fsp_reserve_free_extents. */
2833
fsp_get_available_space_in_free_extents(
2834
/*====================================*/
2835
/* out: available space in kB */
2836
ulint space) /* in: space id */
2838
fsp_header_t* space_header;
2839
ulint n_free_list_ext;
2848
ut_ad(!mutex_own(&kernel_mutex));
2852
latch = fil_space_get_latch(space);
2854
mtr_x_lock(latch, &mtr);
2856
space_header = fsp_get_space_header(space, &mtr);
2858
size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
2860
n_free_list_ext = flst_get_len(space_header + FSP_FREE, &mtr);
2862
free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
2866
if (size < FSP_EXTENT_SIZE) {
2867
ut_a(space != 0); /* This must be a single-table
2870
return(0); /* TODO: count free frag pages and
2871
return a value based on that */
2874
/* Below we play safe when counting free extents above the free limit:
2875
some of them will contain extent descriptor pages, and therefore
2876
will not be free extents */
2878
n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
2880
if (n_free_up > 0) {
2882
n_free_up = n_free_up - n_free_up
2883
/ (XDES_DESCRIBED_PER_PAGE / FSP_EXTENT_SIZE);
2886
n_free = n_free_list_ext + n_free_up;
2888
/* We reserve 1 extent + 0.5 % of the space size to undo logs
2889
and 1 extent + 0.5 % to cleaning operations; NOTE: this source
2890
code is duplicated in the function above! */
2892
reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
2894
if (reserve > n_free) {
2898
return((ullint)(n_free - reserve)
2900
* (UNIV_PAGE_SIZE / 1024));
2903
/************************************************************************
2904
Marks a page used. The page must reside within the extents of the given
2908
fseg_mark_page_used(
2909
/*================*/
2910
fseg_inode_t* seg_inode,/* in: segment inode */
2911
ulint space, /* in: space id */
2912
ulint page, /* in: page offset */
2913
mtr_t* mtr) /* in: mtr */
2916
ulint not_full_n_used;
2918
ut_ad(seg_inode && mtr);
2920
descr = xdes_get_descriptor(space, page, mtr);
2922
ut_ad(mtr_read_ulint(seg_inode + FSEG_ID, MLOG_4BYTES, mtr)
2923
== mtr_read_ulint(descr + XDES_ID, MLOG_4BYTES, mtr));
2925
if (xdes_is_free(descr, mtr)) {
2926
/* We move the extent from the free list to the
2928
flst_remove(seg_inode + FSEG_FREE, descr + XDES_FLST_NODE,
2930
flst_add_last(seg_inode + FSEG_NOT_FULL,
2931
descr + XDES_FLST_NODE, mtr);
2934
ut_ad(xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)
2936
/* We mark the page as used */
2937
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, FALSE, mtr);
2939
not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
2942
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED, not_full_n_used,
2944
if (xdes_is_full(descr, mtr)) {
2945
/* We move the extent from the NOT_FULL list to the
2947
flst_remove(seg_inode + FSEG_NOT_FULL,
2948
descr + XDES_FLST_NODE, mtr);
2949
flst_add_last(seg_inode + FSEG_FULL,
2950
descr + XDES_FLST_NODE, mtr);
2952
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
2953
not_full_n_used - FSP_EXTENT_SIZE,
2958
/**************************************************************************
2959
Frees a single page of a segment. */
2964
fseg_inode_t* seg_inode, /* in: segment inode */
2965
ulint space, /* in: space id */
2966
ulint page, /* in: page offset */
2967
mtr_t* mtr) /* in: mtr handle */
2970
ulint not_full_n_used;
2976
ut_ad(seg_inode && mtr);
2977
ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
2978
== FSEG_MAGIC_N_VALUE);
2980
/* Drop search system page hash index if the page is found in
2981
the pool and is hashed */
2983
btr_search_drop_page_hash_when_freed(space, page);
2985
descr = xdes_get_descriptor(space, page, mtr);
2988
if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
2989
fputs("InnoDB: Dump of the tablespace extent descriptor: ",
2991
ut_print_buf(stderr, descr, 40);
2993
fprintf(stderr, "\n"
2994
"InnoDB: Serious error! InnoDB is trying to"
2996
"InnoDB: though it is already marked as free"
2997
" in the tablespace!\n"
2998
"InnoDB: The tablespace free space info is corrupt.\n"
2999
"InnoDB: You may need to dump your"
3000
" InnoDB tables and recreate the whole\n"
3001
"InnoDB: database!\n", (ulong) page);
3003
fputs("InnoDB: Please refer to\n"
3004
"InnoDB: http://dev.mysql.com/doc/refman/5.1/en/"
3005
"forcing-recovery.html\n"
3006
"InnoDB: about forcing recovery.\n", stderr);
3010
state = xdes_get_state(descr, mtr);
3012
if (state != XDES_FSEG) {
3013
/* The page is in the fragment pages of the segment */
3016
if (fseg_get_nth_frag_page_no(seg_inode, i, mtr)
3019
fseg_set_nth_frag_page_no(seg_inode, i,
3025
fsp_free_page(space, page, mtr);
3030
/* If we get here, the page is in some extent of the segment */
3032
descr_id = mtr_read_dulint(descr + XDES_ID, mtr);
3033
seg_id = mtr_read_dulint(seg_inode + FSEG_ID, mtr);
3036
"InnoDB: InnoDB is freeing space %lu page %lu,\n"
3037
"InnoDB: which belongs to descr seg %lu %lu\n"
3038
"InnoDB: segment %lu %lu.\n",
3039
(ulong) space, (ulong) page,
3040
(ulong) ut_dulint_get_high(descr_id),
3041
(ulong) ut_dulint_get_low(descr_id),
3042
(ulong) ut_dulint_get_high(seg_id),
3043
(ulong) ut_dulint_get_low(seg_id));
3045
if (0 != ut_dulint_cmp(descr_id, seg_id)) {
3046
fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3048
ut_print_buf(stderr, descr, 40);
3049
fputs("\nInnoDB: Dump of the segment inode: ", stderr);
3050
ut_print_buf(stderr, seg_inode, 40);
3054
"InnoDB: Serious error: InnoDB is trying to"
3055
" free space %lu page %lu,\n"
3056
"InnoDB: which does not belong to"
3057
" segment %lu %lu but belongs\n"
3058
"InnoDB: to segment %lu %lu.\n",
3059
(ulong) space, (ulong) page,
3060
(ulong) ut_dulint_get_high(descr_id),
3061
(ulong) ut_dulint_get_low(descr_id),
3062
(ulong) ut_dulint_get_high(seg_id),
3063
(ulong) ut_dulint_get_low(seg_id));
3067
not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3069
if (xdes_is_full(descr, mtr)) {
3070
/* The fragment is full: move it to another list */
3071
flst_remove(seg_inode + FSEG_FULL,
3072
descr + XDES_FLST_NODE, mtr);
3073
flst_add_last(seg_inode + FSEG_NOT_FULL,
3074
descr + XDES_FLST_NODE, mtr);
3075
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3076
not_full_n_used + FSP_EXTENT_SIZE - 1,
3079
ut_a(not_full_n_used > 0);
3080
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3081
not_full_n_used - 1, MLOG_4BYTES, mtr);
3084
xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3085
xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3087
if (xdes_is_free(descr, mtr)) {
3088
/* The extent has become free: free it to space */
3089
flst_remove(seg_inode + FSEG_NOT_FULL,
3090
descr + XDES_FLST_NODE, mtr);
3091
fsp_free_extent(space, page, mtr);
3095
/**************************************************************************
3096
Frees a single page of a segment. */
3101
fseg_header_t* seg_header, /* in: segment header */
3102
ulint space, /* in: space id */
3103
ulint page, /* in: page offset */
3104
mtr_t* mtr) /* in: mtr handle */
3106
fseg_inode_t* seg_inode;
3108
ut_ad(!mutex_own(&kernel_mutex)
3109
|| mtr_memo_contains(mtr, fil_space_get_latch(space),
3112
mtr_x_lock(fil_space_get_latch(space), mtr);
3114
seg_inode = fseg_inode_get(seg_header, mtr);
3116
fseg_free_page_low(seg_inode, space, page, mtr);
3118
#ifdef UNIV_DEBUG_FILE_ACCESSES
3119
buf_page_set_file_page_was_freed(space, page);
3123
/**************************************************************************
3124
Frees an extent of a segment to the space free list. */
3129
fseg_inode_t* seg_inode, /* in: segment inode */
3130
ulint space, /* in: space id */
3131
ulint page, /* in: a page in the extent */
3132
mtr_t* mtr) /* in: mtr handle */
3134
ulint first_page_in_extent;
3136
ulint not_full_n_used;
3140
ut_ad(seg_inode && mtr);
3142
descr = xdes_get_descriptor(space, page, mtr);
3144
ut_a(xdes_get_state(descr, mtr) == XDES_FSEG);
3145
ut_a(0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, mtr),
3146
mtr_read_dulint(seg_inode + FSEG_ID, mtr)));
3148
first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
3150
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3151
if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
3153
/* Drop search system page hash index if the page is
3154
found in the pool and is hashed */
3156
btr_search_drop_page_hash_when_freed(
3157
space, first_page_in_extent + i);
3161
if (xdes_is_full(descr, mtr)) {
3162
flst_remove(seg_inode + FSEG_FULL,
3163
descr + XDES_FLST_NODE, mtr);
3164
} else if (xdes_is_free(descr, mtr)) {
3165
flst_remove(seg_inode + FSEG_FREE,
3166
descr + XDES_FLST_NODE, mtr);
3168
flst_remove(seg_inode + FSEG_NOT_FULL,
3169
descr + XDES_FLST_NODE, mtr);
3171
not_full_n_used = mtr_read_ulint(
3172
seg_inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr);
3174
descr_n_used = xdes_get_n_used(descr, mtr);
3175
ut_a(not_full_n_used >= descr_n_used);
3176
mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3177
not_full_n_used - descr_n_used,
3181
fsp_free_extent(space, page, mtr);
3183
#ifdef UNIV_DEBUG_FILE_ACCESSES
3184
for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3186
buf_page_set_file_page_was_freed(space,
3187
first_page_in_extent + i);
3192
/**************************************************************************
3193
Frees part of a segment. This function can be used to free a segment by
3194
repeatedly calling this function in different mini-transactions. Doing
3195
the freeing in a single mini-transaction might result in too big a
3196
mini-transaction. */
3201
/* out: TRUE if freeing completed */
3202
fseg_header_t* header, /* in, own: segment header; NOTE: if the header
3203
resides on the first page of the frag list
3204
of the segment, this pointer becomes obsolete
3205
after the last freeing step */
3206
mtr_t* mtr) /* in: mtr */
3211
fseg_inode_t* inode;
3214
space = buf_frame_get_space_id(header);
3216
ut_ad(!mutex_own(&kernel_mutex)
3217
|| mtr_memo_contains(mtr, fil_space_get_latch(space),
3220
mtr_x_lock(fil_space_get_latch(space), mtr);
3222
descr = xdes_get_descriptor(space, buf_frame_get_page_no(header), mtr);
3224
/* Check that the header resides on a page which has not been
3228
ut_a(xdes_get_bit(descr, XDES_FREE_BIT, buf_frame_get_page_no(header)
3229
% FSP_EXTENT_SIZE, mtr) == FALSE);
3230
inode = fseg_inode_get(header, mtr);
3232
descr = fseg_get_first_extent(inode, mtr);
3234
if (descr != NULL) {
3235
/* Free the extent held by the segment */
3236
page = xdes_get_offset(descr);
3238
fseg_free_extent(inode, space, page, mtr);
3243
/* Free a frag page */
3244
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3246
if (n == ULINT_UNDEFINED) {
3247
/* Freeing completed: free the segment inode */
3248
fsp_free_seg_inode(space, inode, mtr);
3253
fseg_free_page_low(inode, space,
3254
fseg_get_nth_frag_page_no(inode, n, mtr), mtr);
3256
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3258
if (n == ULINT_UNDEFINED) {
3259
/* Freeing completed: free the segment inode */
3260
fsp_free_seg_inode(space, inode, mtr);
3268
/**************************************************************************
3269
Frees part of a segment. Differs from fseg_free_step because this function
3270
leaves the header page unfreed. */
3273
fseg_free_step_not_header(
3274
/*======================*/
3275
/* out: TRUE if freeing completed, except the
3277
fseg_header_t* header, /* in: segment header which must reside on
3278
the first fragment page of the segment */
3279
mtr_t* mtr) /* in: mtr */
3284
fseg_inode_t* inode;
3288
space = buf_frame_get_space_id(header);
3290
ut_ad(!mutex_own(&kernel_mutex)
3291
|| mtr_memo_contains(mtr, fil_space_get_latch(space),
3294
mtr_x_lock(fil_space_get_latch(space), mtr);
3296
inode = fseg_inode_get(header, mtr);
3298
descr = fseg_get_first_extent(inode, mtr);
3300
if (descr != NULL) {
3301
/* Free the extent held by the segment */
3302
page = xdes_get_offset(descr);
3304
fseg_free_extent(inode, space, page, mtr);
3309
/* Free a frag page */
3311
n = fseg_find_last_used_frag_page_slot(inode, mtr);
3313
if (n == ULINT_UNDEFINED) {
3317
page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
3319
if (page_no == buf_frame_get_page_no(header)) {
3324
fseg_free_page_low(inode, space, page_no, mtr);
3329
/***********************************************************************
3330
Frees a segment. The freeing is performed in several mini-transactions,
3331
so that there is no danger of bufferfixing too many buffer pages. */
3336
ulint space, /* in: space id */
3337
ulint page_no,/* in: page number where the segment header is
3339
ulint offset) /* in: byte offset of the segment header on that
3344
fseg_header_t* header;
3347
addr.page = page_no;
3348
addr.boffset = offset;
3353
header = fut_get_ptr(space, addr, RW_X_LATCH, &mtr);
3355
finished = fseg_free_step(header, &mtr);
3366
/**************************************************************************
3367
Returns the first extent descriptor for a segment. We think of the extent
3368
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
3372
fseg_get_first_extent(
3373
/*==================*/
3374
/* out: the first extent descriptor, or NULL if
3376
fseg_inode_t* inode, /* in: segment inode */
3377
mtr_t* mtr) /* in: mtr */
3383
ut_ad(inode && mtr);
3385
space = buf_frame_get_space_id(inode);
3387
first = fil_addr_null;
3389
if (flst_get_len(inode + FSEG_FULL, mtr) > 0) {
3391
first = flst_get_first(inode + FSEG_FULL, mtr);
3393
} else if (flst_get_len(inode + FSEG_NOT_FULL, mtr) > 0) {
3395
first = flst_get_first(inode + FSEG_NOT_FULL, mtr);
3397
} else if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
3399
first = flst_get_first(inode + FSEG_FREE, mtr);
3402
if (first.page == FIL_NULL) {
3406
descr = xdes_lst_get_descriptor(space, first, mtr);
3411
/***********************************************************************
3412
Validates a segment. */
3417
/* out: TRUE if ok */
3418
fseg_inode_t* inode, /* in: segment inode */
3419
mtr_t* mtr2) /* in: mtr */
3425
fil_addr_t node_addr;
3429
ut_ad(mtr_memo_contains(mtr2, buf_block_align(inode),
3430
MTR_MEMO_PAGE_X_FIX));
3431
ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3433
space = buf_frame_get_space_id(inode);
3435
seg_id = mtr_read_dulint(inode + FSEG_ID, mtr2);
3436
n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3438
flst_validate(inode + FSEG_FREE, mtr2);
3439
flst_validate(inode + FSEG_NOT_FULL, mtr2);
3440
flst_validate(inode + FSEG_FULL, mtr2);
3442
/* Validate FSEG_FREE list */
3443
node_addr = flst_get_first(inode + FSEG_FREE, mtr2);
3445
while (!fil_addr_is_null(node_addr)) {
3447
mtr_x_lock(fil_space_get_latch(space), &mtr);
3449
descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
3451
ut_a(xdes_get_n_used(descr, &mtr) == 0);
3452
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3453
ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr),
3456
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3460
/* Validate FSEG_NOT_FULL list */
3462
node_addr = flst_get_first(inode + FSEG_NOT_FULL, mtr2);
3464
while (!fil_addr_is_null(node_addr)) {
3466
mtr_x_lock(fil_space_get_latch(space), &mtr);
3468
descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
3470
ut_a(xdes_get_n_used(descr, &mtr) > 0);
3471
ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3472
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3473
ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr),
3476
n_used2 += xdes_get_n_used(descr, &mtr);
3478
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3482
/* Validate FSEG_FULL list */
3484
node_addr = flst_get_first(inode + FSEG_FULL, mtr2);
3486
while (!fil_addr_is_null(node_addr)) {
3488
mtr_x_lock(fil_space_get_latch(space), &mtr);
3490
descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
3492
ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
3493
ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3494
ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr),
3497
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3501
ut_a(n_used == n_used2);
3506
/***********************************************************************
3507
Validates a segment. */
3512
/* out: TRUE if ok */
3513
fseg_header_t* header, /* in: segment header */
3514
mtr_t* mtr2) /* in: mtr */
3516
fseg_inode_t* inode;
3520
space = buf_frame_get_space_id(header);
3522
mtr_x_lock(fil_space_get_latch(space), mtr2);
3524
inode = fseg_inode_get(header, mtr2);
3526
ret = fseg_validate_low(inode, mtr2);
3531
/***********************************************************************
3532
Writes info of a segment. */
3537
fseg_inode_t* inode, /* in: segment inode */
3538
mtr_t* mtr) /* in: mtr */
3553
ut_ad(mtr_memo_contains(mtr, buf_block_align(inode),
3554
MTR_MEMO_PAGE_X_FIX));
3555
space = buf_frame_get_space_id(inode);
3556
page_no = buf_frame_get_page_no(inode);
3558
reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
3560
d_var = mtr_read_dulint(inode + FSEG_ID, mtr);
3562
seg_id_low = ut_dulint_get_low(d_var);
3563
seg_id_high = ut_dulint_get_high(d_var);
3565
n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3567
n_frag = fseg_get_n_frag_pages(inode, mtr);
3568
n_free = flst_get_len(inode + FSEG_FREE, mtr);
3569
n_not_full = flst_get_len(inode + FSEG_NOT_FULL, mtr);
3570
n_full = flst_get_len(inode + FSEG_FULL, mtr);
3573
"SEGMENT id %lu %lu space %lu; page %lu;"
3574
" res %lu used %lu; full ext %lu\n"
3575
"fragm pages %lu; free extents %lu;"
3576
" not full extents %lu: pages %lu\n",
3577
(ulong) seg_id_high, (ulong) seg_id_low,
3578
(ulong) space, (ulong) page_no,
3579
(ulong) reserved, (ulong) used, (ulong) n_full,
3580
(ulong) n_frag, (ulong) n_free, (ulong) n_not_full,
3584
/***********************************************************************
3585
Writes info of a segment. */
3590
fseg_header_t* header, /* in: segment header */
3591
mtr_t* mtr) /* in: mtr */
3593
fseg_inode_t* inode;
3596
space = buf_frame_get_space_id(header);
3598
mtr_x_lock(fil_space_get_latch(space), mtr);
3600
inode = fseg_inode_get(header, mtr);
3602
fseg_print_low(inode, mtr);
3605
/***********************************************************************
3606
Validates the file space system and its segments. */
3611
/* out: TRUE if ok */
3612
ulint space) /* in: space id */
3614
fsp_header_t* header;
3615
fseg_inode_t* seg_inode;
3616
page_t* seg_inode_page;
3623
fil_addr_t node_addr;
3624
fil_addr_t next_node_addr;
3625
ulint descr_count = 0;
3628
ulint n_full_frag_pages;
3630
ulint seg_inode_len_free;
3631
ulint seg_inode_len_full;
3633
/* Start first a mini-transaction mtr2 to lock out all other threads
3634
from the fsp system */
3636
mtr_x_lock(fil_space_get_latch(space), &mtr2);
3639
mtr_x_lock(fil_space_get_latch(space), &mtr);
3641
header = fsp_get_space_header(space, &mtr);
3643
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
3644
free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT,
3646
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
3649
n_full_frag_pages = FSP_EXTENT_SIZE
3650
* flst_get_len(header + FSP_FULL_FRAG, &mtr);
3652
if (UNIV_UNLIKELY(free_limit > size)) {
3655
ut_a(size < FSP_EXTENT_SIZE);
3658
flst_validate(header + FSP_FREE, &mtr);
3659
flst_validate(header + FSP_FREE_FRAG, &mtr);
3660
flst_validate(header + FSP_FULL_FRAG, &mtr);
3664
/* Validate FSP_FREE list */
3666
mtr_x_lock(fil_space_get_latch(space), &mtr);
3668
header = fsp_get_space_header(space, &mtr);
3669
node_addr = flst_get_first(header + FSP_FREE, &mtr);
3673
while (!fil_addr_is_null(node_addr)) {
3675
mtr_x_lock(fil_space_get_latch(space), &mtr);
3678
descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
3680
ut_a(xdes_get_n_used(descr, &mtr) == 0);
3681
ut_a(xdes_get_state(descr, &mtr) == XDES_FREE);
3683
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3687
/* Validate FSP_FREE_FRAG list */
3689
mtr_x_lock(fil_space_get_latch(space), &mtr);
3691
header = fsp_get_space_header(space, &mtr);
3692
node_addr = flst_get_first(header + FSP_FREE_FRAG, &mtr);
3696
while (!fil_addr_is_null(node_addr)) {
3698
mtr_x_lock(fil_space_get_latch(space), &mtr);
3701
descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
3703
ut_a(xdes_get_n_used(descr, &mtr) > 0);
3704
ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3705
ut_a(xdes_get_state(descr, &mtr) == XDES_FREE_FRAG);
3707
n_used += xdes_get_n_used(descr, &mtr);
3708
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3713
/* Validate FSP_FULL_FRAG list */
3715
mtr_x_lock(fil_space_get_latch(space), &mtr);
3717
header = fsp_get_space_header(space, &mtr);
3718
node_addr = flst_get_first(header + FSP_FULL_FRAG, &mtr);
3722
while (!fil_addr_is_null(node_addr)) {
3724
mtr_x_lock(fil_space_get_latch(space), &mtr);
3727
descr = xdes_lst_get_descriptor(space, node_addr, &mtr);
3729
ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
3730
ut_a(xdes_get_state(descr, &mtr) == XDES_FULL_FRAG);
3732
node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3736
/* Validate segments */
3738
mtr_x_lock(fil_space_get_latch(space), &mtr);
3740
header = fsp_get_space_header(space, &mtr);
3742
node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
3744
seg_inode_len_full = flst_get_len(header + FSP_SEG_INODES_FULL, &mtr);
3748
while (!fil_addr_is_null(node_addr)) {
3750
for (n = 0; n < FSP_SEG_INODES_PER_PAGE; n++) {
3753
mtr_x_lock(fil_space_get_latch(space), &mtr);
3755
seg_inode_page = fut_get_ptr(
3756
space, node_addr, RW_X_LATCH, &mtr)
3757
- FSEG_INODE_PAGE_NODE;
3759
seg_inode = fsp_seg_inode_page_get_nth_inode(
3760
seg_inode_page, n, &mtr);
3762
mach_read_from_8(seg_inode + FSEG_ID),
3763
ut_dulint_zero) != 0);
3764
fseg_validate_low(seg_inode, &mtr);
3766
descr_count += flst_get_len(seg_inode + FSEG_FREE,
3768
descr_count += flst_get_len(seg_inode + FSEG_FULL,
3770
descr_count += flst_get_len(seg_inode + FSEG_NOT_FULL,
3773
n_used2 += fseg_get_n_frag_pages(seg_inode, &mtr);
3775
next_node_addr = flst_get_next_addr(
3776
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
3780
node_addr = next_node_addr;
3784
mtr_x_lock(fil_space_get_latch(space), &mtr);
3786
header = fsp_get_space_header(space, &mtr);
3788
node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
3790
seg_inode_len_free = flst_get_len(header + FSP_SEG_INODES_FREE, &mtr);
3794
while (!fil_addr_is_null(node_addr)) {
3796
for (n = 0; n < FSP_SEG_INODES_PER_PAGE; n++) {
3799
mtr_x_lock(fil_space_get_latch(space), &mtr);
3801
seg_inode_page = fut_get_ptr(
3802
space, node_addr, RW_X_LATCH, &mtr)
3803
- FSEG_INODE_PAGE_NODE;
3805
seg_inode = fsp_seg_inode_page_get_nth_inode(
3806
seg_inode_page, n, &mtr);
3808
mach_read_from_8(seg_inode + FSEG_ID),
3809
ut_dulint_zero) != 0) {
3810
fseg_validate_low(seg_inode, &mtr);
3812
descr_count += flst_get_len(
3813
seg_inode + FSEG_FREE, &mtr);
3814
descr_count += flst_get_len(
3815
seg_inode + FSEG_FULL, &mtr);
3816
descr_count += flst_get_len(
3817
seg_inode + FSEG_NOT_FULL, &mtr);
3818
n_used2 += fseg_get_n_frag_pages(
3822
next_node_addr = flst_get_next_addr(
3823
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
3827
node_addr = next_node_addr;
3830
ut_a(descr_count * FSP_EXTENT_SIZE == free_limit);
3831
ut_a(n_used + n_full_frag_pages
3832
== n_used2 + 2* ((free_limit + XDES_DESCRIBED_PER_PAGE - 1)
3833
/ XDES_DESCRIBED_PER_PAGE)
3834
+ seg_inode_len_full + seg_inode_len_free);
3835
ut_a(frag_n_used == n_used);
3842
/***********************************************************************
3843
Prints info of a file space. */
3848
ulint space) /* in: space id */
3850
fsp_header_t* header;
3851
fseg_inode_t* seg_inode;
3852
page_t* seg_inode_page;
3856
fil_addr_t node_addr;
3857
fil_addr_t next_node_addr;
3869
/* Start first a mini-transaction mtr2 to lock out all other threads
3870
from the fsp system */
3874
mtr_x_lock(fil_space_get_latch(space), &mtr2);
3878
mtr_x_lock(fil_space_get_latch(space), &mtr);
3880
header = fsp_get_space_header(space, &mtr);
3882
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
3884
free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES,
3886
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
3888
n_free = flst_get_len(header + FSP_FREE, &mtr);
3889
n_free_frag = flst_get_len(header + FSP_FREE_FRAG, &mtr);
3890
n_full_frag = flst_get_len(header + FSP_FULL_FRAG, &mtr);
3892
d_var = mtr_read_dulint(header + FSP_SEG_ID, &mtr);
3894
seg_id_low = ut_dulint_get_low(d_var);
3895
seg_id_high = ut_dulint_get_high(d_var);
3898
"FILE SPACE INFO: id %lu\n"
3899
"size %lu, free limit %lu, free extents %lu\n"
3900
"not full frag extents %lu: used pages %lu,"
3901
" full frag extents %lu\n"
3902
"first seg id not used %lu %lu\n",
3904
(ulong) size, (ulong) free_limit, (ulong) n_free,
3905
(ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag,
3906
(ulong) seg_id_high, (ulong) seg_id_low);
3910
/* Print segments */
3913
mtr_x_lock(fil_space_get_latch(space), &mtr);
3915
header = fsp_get_space_header(space, &mtr);
3917
node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
3921
while (!fil_addr_is_null(node_addr)) {
3923
for (n = 0; n < FSP_SEG_INODES_PER_PAGE; n++) {
3926
mtr_x_lock(fil_space_get_latch(space), &mtr);
3928
seg_inode_page = fut_get_ptr(
3929
space, node_addr, RW_X_LATCH, &mtr)
3930
- FSEG_INODE_PAGE_NODE;
3932
seg_inode = fsp_seg_inode_page_get_nth_inode(
3933
seg_inode_page, n, &mtr);
3935
mach_read_from_8(seg_inode + FSEG_ID),
3936
ut_dulint_zero) != 0);
3937
fseg_print_low(seg_inode, &mtr);
3941
next_node_addr = flst_get_next_addr(
3942
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
3946
node_addr = next_node_addr;
3950
mtr_x_lock(fil_space_get_latch(space), &mtr);
3952
header = fsp_get_space_header(space, &mtr);
3954
node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
3958
while (!fil_addr_is_null(node_addr)) {
3960
for (n = 0; n < FSP_SEG_INODES_PER_PAGE; n++) {
3963
mtr_x_lock(fil_space_get_latch(space), &mtr);
3965
seg_inode_page = fut_get_ptr(
3966
space, node_addr, RW_X_LATCH, &mtr)
3967
- FSEG_INODE_PAGE_NODE;
3969
seg_inode = fsp_seg_inode_page_get_nth_inode(
3970
seg_inode_page, n, &mtr);
3972
mach_read_from_8(seg_inode + FSEG_ID),
3973
ut_dulint_zero) != 0) {
3975
fseg_print_low(seg_inode, &mtr);
3979
next_node_addr = flst_get_next_addr(
3980
seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
3984
node_addr = next_node_addr;
3989
fprintf(stderr, "NUMBER of file segments: %lu\n", (ulong) n_segs);