~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/innobase/fsp/fsp0fsp.c

  • Committer: Patrick Crews
  • Date: 2010-07-19 22:50:20 UTC
  • mto: (1663.1.2 rollup)
  • mto: This revision was merged to the branch mainline in revision 1664.
  • Revision ID: gleebix@gmail.com-20100719225020-6lhrjnkq3k9lyq0f
Fix of optimizer.test - needed cleanup at the end + updated .result file

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*****************************************************************************
2
 
 
3
 
Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
4
 
 
5
 
This program is free software; you can redistribute it and/or modify it under
6
 
the terms of the GNU General Public License as published by the Free Software
7
 
Foundation; version 2 of the License.
8
 
 
9
 
This program is distributed in the hope that it will be useful, but WITHOUT
10
 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
 
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
 
 
13
 
You should have received a copy of the GNU General Public License along with
14
 
this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
15
 
St, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
*****************************************************************************/
18
 
 
19
 
/******************************************************************//**
20
 
@file fsp/fsp0fsp.c
21
 
File space management
22
 
 
23
 
Created 11/29/1995 Heikki Tuuri
24
 
***********************************************************************/
25
 
 
26
 
#include "fsp0fsp.h"
27
 
 
28
 
#ifdef UNIV_NONINL
29
 
#include "fsp0fsp.ic"
30
 
#endif
31
 
 
32
 
#include "buf0buf.h"
33
 
#include "fil0fil.h"
34
 
#include "mtr0log.h"
35
 
#include "ut0byte.h"
36
 
#include "page0page.h"
37
 
#include "page0zip.h"
38
 
#ifdef UNIV_HOTBACKUP
39
 
# include "fut0lst.h"
40
 
#else /* UNIV_HOTBACKUP */
41
 
# include "sync0sync.h"
42
 
# include "fut0fut.h"
43
 
# include "srv0srv.h"
44
 
# include "ibuf0ibuf.h"
45
 
# include "btr0btr.h"
46
 
# include "btr0sea.h"
47
 
# include "dict0boot.h"
48
 
# include "log0log.h"
49
 
#endif /* UNIV_HOTBACKUP */
50
 
#include "dict0mem.h"
51
 
 
52
 
 
53
 
#define FSP_HEADER_OFFSET       FIL_PAGE_DATA   /* Offset of the space header
54
 
                                                within a file page */
55
 
 
56
 
/* The data structures in files are defined just as byte strings in C */
57
 
typedef byte    fsp_header_t;
58
 
typedef byte    xdes_t;
59
 
 
60
 
/*                      SPACE HEADER
61
 
                        ============
62
 
 
63
 
File space header data structure: this data structure is contained in the
64
 
first page of a space. The space for this header is reserved in every extent
65
 
descriptor page, but used only in the first. */
66
 
 
67
 
/*-------------------------------------*/
68
 
#define FSP_SPACE_ID            0       /* space id */
69
 
#define FSP_NOT_USED            4       /* this field contained a value up to
70
 
                                        which we know that the modifications
71
 
                                        in the database have been flushed to
72
 
                                        the file space; not used now */
73
 
#define FSP_SIZE                8       /* Current size of the space in
74
 
                                        pages */
75
 
#define FSP_FREE_LIMIT          12      /* Minimum page number for which the
76
 
                                        free list has not been initialized:
77
 
                                        the pages >= this limit are, by
78
 
                                        definition, free; note that in a
79
 
                                        single-table tablespace where size
80
 
                                        < 64 pages, this number is 64, i.e.,
81
 
                                        we have initialized the space
82
 
                                        about the first extent, but have not
83
 
                                        physically allocted those pages to the
84
 
                                        file */
85
 
#define FSP_SPACE_FLAGS         16      /* table->flags & ~DICT_TF_COMPACT */
86
 
#define FSP_FRAG_N_USED         20      /* number of used pages in the
87
 
                                        FSP_FREE_FRAG list */
88
 
#define FSP_FREE                24      /* list of free extents */
89
 
#define FSP_FREE_FRAG           (24 + FLST_BASE_NODE_SIZE)
90
 
                                        /* list of partially free extents not
91
 
                                        belonging to any segment */
92
 
#define FSP_FULL_FRAG           (24 + 2 * FLST_BASE_NODE_SIZE)
93
 
                                        /* list of full extents not belonging
94
 
                                        to any segment */
95
 
#define FSP_SEG_ID              (24 + 3 * FLST_BASE_NODE_SIZE)
96
 
                                        /* 8 bytes which give the first unused
97
 
                                        segment id */
98
 
#define FSP_SEG_INODES_FULL     (32 + 3 * FLST_BASE_NODE_SIZE)
99
 
                                        /* list of pages containing segment
100
 
                                        headers, where all the segment inode
101
 
                                        slots are reserved */
102
 
#define FSP_SEG_INODES_FREE     (32 + 4 * FLST_BASE_NODE_SIZE)
103
 
                                        /* list of pages containing segment
104
 
                                        headers, where not all the segment
105
 
                                        header slots are reserved */
106
 
/*-------------------------------------*/
107
 
/* File space header size */
108
 
#define FSP_HEADER_SIZE         (32 + 5 * FLST_BASE_NODE_SIZE)
109
 
 
110
 
#define FSP_FREE_ADD            4       /* this many free extents are added
111
 
                                        to the free list from above
112
 
                                        FSP_FREE_LIMIT at a time */
113
 
 
114
 
/*                      FILE SEGMENT INODE
115
 
                        ==================
116
 
 
117
 
Segment inode which is created for each segment in a tablespace. NOTE: in
118
 
purge we assume that a segment having only one currently used page can be
119
 
freed in a few steps, so that the freeing cannot fill the file buffer with
120
 
bufferfixed file pages. */
121
 
 
122
 
typedef byte    fseg_inode_t;
123
 
 
124
 
#define FSEG_INODE_PAGE_NODE    FSEG_PAGE_DATA
125
 
                                        /* the list node for linking
126
 
                                        segment inode pages */
127
 
 
128
 
#define FSEG_ARR_OFFSET         (FSEG_PAGE_DATA + FLST_NODE_SIZE)
129
 
/*-------------------------------------*/
130
 
#define FSEG_ID                 0       /* 8 bytes of segment id: if this is 0,
131
 
                                        it means that the header is unused */
132
 
#define FSEG_NOT_FULL_N_USED    8
133
 
                                        /* number of used segment pages in
134
 
                                        the FSEG_NOT_FULL list */
135
 
#define FSEG_FREE               12
136
 
                                        /* list of free extents of this
137
 
                                        segment */
138
 
#define FSEG_NOT_FULL           (12 + FLST_BASE_NODE_SIZE)
139
 
                                        /* list of partially free extents */
140
 
#define FSEG_FULL               (12 + 2 * FLST_BASE_NODE_SIZE)
141
 
                                        /* list of full extents */
142
 
#define FSEG_MAGIC_N            (12 + 3 * FLST_BASE_NODE_SIZE)
143
 
                                        /* magic number used in debugging */
144
 
#define FSEG_FRAG_ARR           (16 + 3 * FLST_BASE_NODE_SIZE)
145
 
                                        /* array of individual pages
146
 
                                        belonging to this segment in fsp
147
 
                                        fragment extent lists */
148
 
#define FSEG_FRAG_ARR_N_SLOTS   (FSP_EXTENT_SIZE / 2)
149
 
                                        /* number of slots in the array for
150
 
                                        the fragment pages */
151
 
#define FSEG_FRAG_SLOT_SIZE     4       /* a fragment page slot contains its
152
 
                                        page number within space, FIL_NULL
153
 
                                        means that the slot is not in use */
154
 
/*-------------------------------------*/
155
 
#define FSEG_INODE_SIZE                                 \
156
 
        (16 + 3 * FLST_BASE_NODE_SIZE                   \
157
 
         + FSEG_FRAG_ARR_N_SLOTS * FSEG_FRAG_SLOT_SIZE)
158
 
 
159
 
#define FSP_SEG_INODES_PER_PAGE(zip_size)               \
160
 
        (((zip_size ? zip_size : UNIV_PAGE_SIZE)        \
161
 
          - FSEG_ARR_OFFSET - 10) / FSEG_INODE_SIZE)
162
 
                                /* Number of segment inodes which fit on a
163
 
                                single page */
164
 
 
165
 
#define FSEG_MAGIC_N_VALUE      97937874
166
 
 
167
 
#define FSEG_FILLFACTOR         8       /* If this value is x, then if
168
 
                                        the number of unused but reserved
169
 
                                        pages in a segment is less than
170
 
                                        reserved pages * 1/x, and there are
171
 
                                        at least FSEG_FRAG_LIMIT used pages,
172
 
                                        then we allow a new empty extent to
173
 
                                        be added to the segment in
174
 
                                        fseg_alloc_free_page. Otherwise, we
175
 
                                        use unused pages of the segment. */
176
 
 
177
 
#define FSEG_FRAG_LIMIT         FSEG_FRAG_ARR_N_SLOTS
178
 
                                        /* If the segment has >= this many
179
 
                                        used pages, it may be expanded by
180
 
                                        allocating extents to the segment;
181
 
                                        until that only individual fragment
182
 
                                        pages are allocated from the space */
183
 
 
184
 
#define FSEG_FREE_LIST_LIMIT    40      /* If the reserved size of a segment
185
 
                                        is at least this many extents, we
186
 
                                        allow extents to be put to the free
187
 
                                        list of the extent: at most
188
 
                                        FSEG_FREE_LIST_MAX_LEN many */
189
 
#define FSEG_FREE_LIST_MAX_LEN  4
190
 
 
191
 
 
192
 
/*                      EXTENT DESCRIPTOR
193
 
                        =================
194
 
 
195
 
File extent descriptor data structure: contains bits to tell which pages in
196
 
the extent are free and which contain old tuple version to clean. */
197
 
 
198
 
/*-------------------------------------*/
199
 
#define XDES_ID                 0       /* The identifier of the segment
200
 
                                        to which this extent belongs */
201
 
#define XDES_FLST_NODE          8       /* The list node data structure
202
 
                                        for the descriptors */
203
 
#define XDES_STATE              (FLST_NODE_SIZE + 8)
204
 
                                        /* contains state information
205
 
                                        of the extent */
206
 
#define XDES_BITMAP             (FLST_NODE_SIZE + 12)
207
 
                                        /* Descriptor bitmap of the pages
208
 
                                        in the extent */
209
 
/*-------------------------------------*/
210
 
 
211
 
#define XDES_BITS_PER_PAGE      2       /* How many bits are there per page */
212
 
#define XDES_FREE_BIT           0       /* Index of the bit which tells if
213
 
                                        the page is free */
214
 
#define XDES_CLEAN_BIT          1       /* NOTE: currently not used!
215
 
                                        Index of the bit which tells if
216
 
                                        there are old versions of tuples
217
 
                                        on the page */
218
 
/* States of a descriptor */
219
 
#define XDES_FREE               1       /* extent is in free list of space */
220
 
#define XDES_FREE_FRAG          2       /* extent is in free fragment list of
221
 
                                        space */
222
 
#define XDES_FULL_FRAG          3       /* extent is in full fragment list of
223
 
                                        space */
224
 
#define XDES_FSEG               4       /* extent belongs to a segment */
225
 
 
226
 
/* File extent data structure size in bytes. */
227
 
#define XDES_SIZE                                                       \
228
 
        (XDES_BITMAP + UT_BITS_IN_BYTES(FSP_EXTENT_SIZE * XDES_BITS_PER_PAGE))
229
 
 
230
 
/* Offset of the descriptor array on a descriptor page */
231
 
#define XDES_ARR_OFFSET         (FSP_HEADER_OFFSET + FSP_HEADER_SIZE)
232
 
 
233
 
#ifndef UNIV_HOTBACKUP
234
 
/* Flag to indicate if we have printed the tablespace full error. */
235
 
static ibool fsp_tbs_full_error_printed = FALSE;
236
 
 
237
 
/**********************************************************************//**
238
 
Returns an extent to the free list of a space. */
239
 
static
240
 
void
241
 
fsp_free_extent(
242
 
/*============*/
243
 
        ulint           space,  /*!< in: space id */
244
 
        ulint           zip_size,/*!< in: compressed page size in bytes
245
 
                                or 0 for uncompressed pages */
246
 
        ulint           page,   /*!< in: page offset in the extent */
247
 
        mtr_t*          mtr);   /*!< in: mtr */
248
 
/**********************************************************************//**
249
 
Frees an extent of a segment to the space free list. */
250
 
static
251
 
void
252
 
fseg_free_extent(
253
 
/*=============*/
254
 
        fseg_inode_t*   seg_inode, /*!< in: segment inode */
255
 
        ulint           space,  /*!< in: space id */
256
 
        ulint           zip_size,/*!< in: compressed page size in bytes
257
 
                                or 0 for uncompressed pages */
258
 
        ulint           page,   /*!< in: page offset in the extent */
259
 
        mtr_t*          mtr);   /*!< in: mtr handle */
260
 
/**********************************************************************//**
261
 
Calculates the number of pages reserved by a segment, and how
262
 
many pages are currently used.
263
 
@return number of reserved pages */
264
 
static
265
 
ulint
266
 
fseg_n_reserved_pages_low(
267
 
/*======================*/
268
 
        fseg_inode_t*   header, /*!< in: segment inode */
269
 
        ulint*          used,   /*!< out: number of pages used (not
270
 
                                more than reserved) */
271
 
        mtr_t*          mtr);   /*!< in: mtr handle */
272
 
/********************************************************************//**
273
 
Marks a page used. The page must reside within the extents of the given
274
 
segment. */
275
 
static
276
 
void
277
 
fseg_mark_page_used(
278
 
/*================*/
279
 
        fseg_inode_t*   seg_inode,/*!< in: segment inode */
280
 
        ulint           space,  /*!< in: space id */
281
 
        ulint           zip_size,/*!< in: compressed page size in bytes
282
 
                                or 0 for uncompressed pages */
283
 
        ulint           page,   /*!< in: page offset */
284
 
        mtr_t*          mtr);   /*!< in: mtr */
285
 
/**********************************************************************//**
286
 
Returns the first extent descriptor for a segment. We think of the extent
287
 
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
288
 
-> FSEG_FREE.
289
 
@return the first extent descriptor, or NULL if none */
290
 
static
291
 
xdes_t*
292
 
fseg_get_first_extent(
293
 
/*==================*/
294
 
        fseg_inode_t*   inode,  /*!< in: segment inode */
295
 
        ulint           space,  /*!< in: space id */
296
 
        ulint           zip_size,/*!< in: compressed page size in bytes
297
 
                                or 0 for uncompressed pages */
298
 
        mtr_t*          mtr);   /*!< in: mtr */
299
 
/**********************************************************************//**
300
 
Puts new extents to the free list if
301
 
there are free extents above the free limit. If an extent happens
302
 
to contain an extent descriptor page, the extent is put to
303
 
the FSP_FREE_FRAG list with the page marked as used. */
304
 
static
305
 
void
306
 
fsp_fill_free_list(
307
 
/*===============*/
308
 
        ibool           init_space,     /*!< in: TRUE if this is a single-table
309
 
                                        tablespace and we are only initing
310
 
                                        the tablespace's first extent
311
 
                                        descriptor page and ibuf bitmap page;
312
 
                                        then we do not allocate more extents */
313
 
        ulint           space,          /*!< in: space */
314
 
        fsp_header_t*   header,         /*!< in: space header */
315
 
        mtr_t*          mtr);           /*!< in: mtr */
316
 
/**********************************************************************//**
317
 
Allocates a single free page from a segment. This function implements
318
 
the intelligent allocation strategy which tries to minimize file space
319
 
fragmentation.
320
 
@return the allocated page number, FIL_NULL if no page could be allocated */
321
 
static
322
 
ulint
323
 
fseg_alloc_free_page_low(
324
 
/*=====================*/
325
 
        ulint           space,  /*!< in: space */
326
 
        ulint           zip_size,/*!< in: compressed page size in bytes
327
 
                                or 0 for uncompressed pages */
328
 
        fseg_inode_t*   seg_inode, /*!< in: segment inode */
329
 
        ulint           hint,   /*!< in: hint of which page would be desirable */
330
 
        byte            direction, /*!< in: if the new page is needed because
331
 
                                of an index page split, and records are
332
 
                                inserted there in order, into which
333
 
                                direction they go alphabetically: FSP_DOWN,
334
 
                                FSP_UP, FSP_NO_DIR */
335
 
        mtr_t*          mtr);   /*!< in: mtr handle */
336
 
#endif /* !UNIV_HOTBACKUP */
337
 
 
338
 
/**********************************************************************//**
339
 
Reads the file space size stored in the header page.
340
 
@return tablespace size stored in the space header */
341
 
UNIV_INTERN
342
 
ulint
343
 
fsp_get_size_low(
344
 
/*=============*/
345
 
        page_t* page)   /*!< in: header page (page 0 in the tablespace) */
346
 
{
347
 
        return(mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SIZE));
348
 
}
349
 
 
350
 
#ifndef UNIV_HOTBACKUP
351
 
/**********************************************************************//**
352
 
Gets a pointer to the space header and x-locks its page.
353
 
@return pointer to the space header, page x-locked */
354
 
UNIV_INLINE
355
 
fsp_header_t*
356
 
fsp_get_space_header(
357
 
/*=================*/
358
 
        ulint   id,     /*!< in: space id */
359
 
        ulint   zip_size,/*!< in: compressed page size in bytes
360
 
                        or 0 for uncompressed pages */
361
 
        mtr_t*  mtr)    /*!< in: mtr */
362
 
{
363
 
        buf_block_t*    block;
364
 
        fsp_header_t*   header;
365
 
 
366
 
        ut_ad(ut_is_2pow(zip_size));
367
 
        ut_ad(zip_size <= UNIV_PAGE_SIZE);
368
 
        ut_ad(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
369
 
        ut_ad(id || !zip_size);
370
 
 
371
 
        block = buf_page_get(id, zip_size, 0, RW_X_LATCH, mtr);
372
 
        header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
373
 
        buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
374
 
 
375
 
        ut_ad(id == mach_read_from_4(FSP_SPACE_ID + header));
376
 
        ut_ad(zip_size == dict_table_flags_to_zip_size(
377
 
                      mach_read_from_4(FSP_SPACE_FLAGS + header)));
378
 
        return(header);
379
 
}
380
 
 
381
 
/**********************************************************************//**
382
 
Gets a descriptor bit of a page.
383
 
@return TRUE if free */
384
 
UNIV_INLINE
385
 
ibool
386
 
xdes_get_bit(
387
 
/*=========*/
388
 
        const xdes_t*   descr,  /*!< in: descriptor */
389
 
        ulint           bit,    /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
390
 
        ulint           offset, /*!< in: page offset within extent:
391
 
                                0 ... FSP_EXTENT_SIZE - 1 */
392
 
        mtr_t*          mtr)    /*!< in: mtr */
393
 
{
394
 
        ulint   index;
395
 
        ulint   byte_index;
396
 
        ulint   bit_index;
397
 
 
398
 
        ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
399
 
        ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
400
 
        ut_ad(offset < FSP_EXTENT_SIZE);
401
 
 
402
 
        index = bit + XDES_BITS_PER_PAGE * offset;
403
 
 
404
 
        byte_index = index / 8;
405
 
        bit_index = index % 8;
406
 
 
407
 
        return(ut_bit_get_nth(mtr_read_ulint(descr + XDES_BITMAP + byte_index,
408
 
                                             MLOG_1BYTE, mtr),
409
 
                              bit_index));
410
 
}
411
 
 
412
 
/**********************************************************************//**
413
 
Sets a descriptor bit of a page. */
414
 
UNIV_INLINE
415
 
void
416
 
xdes_set_bit(
417
 
/*=========*/
418
 
        xdes_t* descr,  /*!< in: descriptor */
419
 
        ulint   bit,    /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
420
 
        ulint   offset, /*!< in: page offset within extent:
421
 
                        0 ... FSP_EXTENT_SIZE - 1 */
422
 
        ibool   val,    /*!< in: bit value */
423
 
        mtr_t*  mtr)    /*!< in: mtr */
424
 
{
425
 
        ulint   index;
426
 
        ulint   byte_index;
427
 
        ulint   bit_index;
428
 
        ulint   descr_byte;
429
 
 
430
 
        ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
431
 
        ut_ad((bit == XDES_FREE_BIT) || (bit == XDES_CLEAN_BIT));
432
 
        ut_ad(offset < FSP_EXTENT_SIZE);
433
 
 
434
 
        index = bit + XDES_BITS_PER_PAGE * offset;
435
 
 
436
 
        byte_index = index / 8;
437
 
        bit_index = index % 8;
438
 
 
439
 
        descr_byte = mtr_read_ulint(descr + XDES_BITMAP + byte_index,
440
 
                                    MLOG_1BYTE, mtr);
441
 
        descr_byte = ut_bit_set_nth(descr_byte, bit_index, val);
442
 
 
443
 
        mlog_write_ulint(descr + XDES_BITMAP + byte_index, descr_byte,
444
 
                         MLOG_1BYTE, mtr);
445
 
}
446
 
 
447
 
/**********************************************************************//**
448
 
Looks for a descriptor bit having the desired value. Starts from hint
449
 
and scans upward; at the end of the extent the search is wrapped to
450
 
the start of the extent.
451
 
@return bit index of the bit, ULINT_UNDEFINED if not found */
452
 
UNIV_INLINE
453
 
ulint
454
 
xdes_find_bit(
455
 
/*==========*/
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 */
461
 
{
462
 
        ulint   i;
463
 
 
464
 
        ut_ad(descr && mtr);
465
 
        ut_ad(val <= TRUE);
466
 
        ut_ad(hint < FSP_EXTENT_SIZE);
467
 
        ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
468
 
        for (i = hint; i < FSP_EXTENT_SIZE; i++) {
469
 
                if (val == xdes_get_bit(descr, bit, i, mtr)) {
470
 
 
471
 
                        return(i);
472
 
                }
473
 
        }
474
 
 
475
 
        for (i = 0; i < hint; i++) {
476
 
                if (val == xdes_get_bit(descr, bit, i, mtr)) {
477
 
 
478
 
                        return(i);
479
 
                }
480
 
        }
481
 
 
482
 
        return(ULINT_UNDEFINED);
483
 
}
484
 
 
485
 
/**********************************************************************//**
486
 
Looks for a descriptor bit having the desired value. Scans the extent in
487
 
a direction opposite to xdes_find_bit.
488
 
@return bit index of the bit, ULINT_UNDEFINED if not found */
489
 
UNIV_INLINE
490
 
ulint
491
 
xdes_find_bit_downward(
492
 
/*===================*/
493
 
        xdes_t* descr,  /*!< in: descriptor */
494
 
        ulint   bit,    /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
495
 
        ibool   val,    /*!< in: desired bit value */
496
 
        ulint   hint,   /*!< in: hint of which bit position would be desirable */
497
 
        mtr_t*  mtr)    /*!< in: mtr */
498
 
{
499
 
        ulint   i;
500
 
 
501
 
        ut_ad(descr && mtr);
502
 
        ut_ad(val <= TRUE);
503
 
        ut_ad(hint < FSP_EXTENT_SIZE);
504
 
        ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
505
 
        for (i = hint + 1; i > 0; i--) {
506
 
                if (val == xdes_get_bit(descr, bit, i - 1, mtr)) {
507
 
 
508
 
                        return(i - 1);
509
 
                }
510
 
        }
511
 
 
512
 
        for (i = FSP_EXTENT_SIZE - 1; i > hint; i--) {
513
 
                if (val == xdes_get_bit(descr, bit, i, mtr)) {
514
 
 
515
 
                        return(i);
516
 
                }
517
 
        }
518
 
 
519
 
        return(ULINT_UNDEFINED);
520
 
}
521
 
 
522
 
/**********************************************************************//**
523
 
Returns the number of used pages in a descriptor.
524
 
@return number of pages used */
525
 
UNIV_INLINE
526
 
ulint
527
 
xdes_get_n_used(
528
 
/*============*/
529
 
        const xdes_t*   descr,  /*!< in: descriptor */
530
 
        mtr_t*          mtr)    /*!< in: mtr */
531
 
{
532
 
        ulint   i;
533
 
        ulint   count   = 0;
534
 
 
535
 
        ut_ad(descr && mtr);
536
 
        ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
537
 
        for (i = 0; i < FSP_EXTENT_SIZE; i++) {
538
 
                if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
539
 
                        count++;
540
 
                }
541
 
        }
542
 
 
543
 
        return(count);
544
 
}
545
 
 
546
 
/**********************************************************************//**
547
 
Returns true if extent contains no used pages.
548
 
@return TRUE if totally free */
549
 
UNIV_INLINE
550
 
ibool
551
 
xdes_is_free(
552
 
/*=========*/
553
 
        const xdes_t*   descr,  /*!< in: descriptor */
554
 
        mtr_t*          mtr)    /*!< in: mtr */
555
 
{
556
 
        if (0 == xdes_get_n_used(descr, mtr)) {
557
 
 
558
 
                return(TRUE);
559
 
        }
560
 
 
561
 
        return(FALSE);
562
 
}
563
 
 
564
 
/**********************************************************************//**
565
 
Returns true if extent contains no free pages.
566
 
@return TRUE if full */
567
 
UNIV_INLINE
568
 
ibool
569
 
xdes_is_full(
570
 
/*=========*/
571
 
        const xdes_t*   descr,  /*!< in: descriptor */
572
 
        mtr_t*          mtr)    /*!< in: mtr */
573
 
{
574
 
        if (FSP_EXTENT_SIZE == xdes_get_n_used(descr, mtr)) {
575
 
 
576
 
                return(TRUE);
577
 
        }
578
 
 
579
 
        return(FALSE);
580
 
}
581
 
 
582
 
/**********************************************************************//**
583
 
Sets the state of an xdes. */
584
 
UNIV_INLINE
585
 
void
586
 
xdes_set_state(
587
 
/*===========*/
588
 
        xdes_t* descr,  /*!< in/out: descriptor */
589
 
        ulint   state,  /*!< in: state to set */
590
 
        mtr_t*  mtr)    /*!< in: mtr handle */
591
 
{
592
 
        ut_ad(descr && mtr);
593
 
        ut_ad(state >= XDES_FREE);
594
 
        ut_ad(state <= XDES_FSEG);
595
 
        ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
596
 
 
597
 
        mlog_write_ulint(descr + XDES_STATE, state, MLOG_4BYTES, mtr);
598
 
}
599
 
 
600
 
/**********************************************************************//**
601
 
Gets the state of an xdes.
602
 
@return state */
603
 
UNIV_INLINE
604
 
ulint
605
 
xdes_get_state(
606
 
/*===========*/
607
 
        const xdes_t*   descr,  /*!< in: descriptor */
608
 
        mtr_t*          mtr)    /*!< in: mtr handle */
609
 
{
610
 
        ulint   state;
611
 
 
612
 
        ut_ad(descr && mtr);
613
 
        ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
614
 
 
615
 
        state = mtr_read_ulint(descr + XDES_STATE, MLOG_4BYTES, mtr);
616
 
        ut_ad(state - 1 < XDES_FSEG);
617
 
        return(state);
618
 
}
619
 
 
620
 
/**********************************************************************//**
621
 
Inits an extent descriptor to the free and clean state. */
622
 
UNIV_INLINE
623
 
void
624
 
xdes_init(
625
 
/*======*/
626
 
        xdes_t* descr,  /*!< in: descriptor */
627
 
        mtr_t*  mtr)    /*!< in: mtr */
628
 
{
629
 
        ulint   i;
630
 
 
631
 
        ut_ad(descr && mtr);
632
 
        ut_ad(mtr_memo_contains_page(mtr, descr, MTR_MEMO_PAGE_X_FIX));
633
 
        ut_ad((XDES_SIZE - XDES_BITMAP) % 4 == 0);
634
 
 
635
 
        for (i = XDES_BITMAP; i < XDES_SIZE; i += 4) {
636
 
                mlog_write_ulint(descr + i, 0xFFFFFFFFUL, MLOG_4BYTES, mtr);
637
 
        }
638
 
 
639
 
        xdes_set_state(descr, XDES_FREE, mtr);
640
 
}
641
 
 
642
 
/********************************************************************//**
643
 
Calculates the page where the descriptor of a page resides.
644
 
@return descriptor page offset */
645
 
UNIV_INLINE
646
 
ulint
647
 
xdes_calc_descriptor_page(
648
 
/*======================*/
649
 
        ulint   zip_size,       /*!< in: compressed page size in bytes;
650
 
                                0 for uncompressed pages */
651
 
        ulint   offset)         /*!< in: page offset */
652
 
{
653
 
#ifndef DOXYGEN /* Doxygen gets confused of these */
654
 
# if UNIV_PAGE_SIZE <= XDES_ARR_OFFSET \
655
 
                + (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
656
 
#  error
657
 
# endif
658
 
# if PAGE_ZIP_MIN_SIZE <= XDES_ARR_OFFSET \
659
 
                + (PAGE_ZIP_MIN_SIZE / FSP_EXTENT_SIZE) * XDES_SIZE
660
 
#  error
661
 
# endif
662
 
#endif /* !DOXYGEN */
663
 
        ut_ad(ut_is_2pow(zip_size));
664
 
 
665
 
        if (!zip_size) {
666
 
                return(ut_2pow_round(offset, UNIV_PAGE_SIZE));
667
 
        } else {
668
 
                ut_ad(zip_size > XDES_ARR_OFFSET
669
 
                      + (zip_size / FSP_EXTENT_SIZE) * XDES_SIZE);
670
 
                return(ut_2pow_round(offset, zip_size));
671
 
        }
672
 
}
673
 
 
674
 
/********************************************************************//**
675
 
Calculates the descriptor index within a descriptor page.
676
 
@return descriptor index */
677
 
UNIV_INLINE
678
 
ulint
679
 
xdes_calc_descriptor_index(
680
 
/*=======================*/
681
 
        ulint   zip_size,       /*!< in: compressed page size in bytes;
682
 
                                0 for uncompressed pages */
683
 
        ulint   offset)         /*!< in: page offset */
684
 
{
685
 
        ut_ad(ut_is_2pow(zip_size));
686
 
 
687
 
        if (!zip_size) {
688
 
                return(ut_2pow_remainder(offset, UNIV_PAGE_SIZE)
689
 
                       / FSP_EXTENT_SIZE);
690
 
        } else {
691
 
                return(ut_2pow_remainder(offset, zip_size) / FSP_EXTENT_SIZE);
692
 
        }
693
 
}
694
 
 
695
 
/********************************************************************//**
696
 
Gets pointer to a the extent descriptor of a page. The page where the extent
697
 
descriptor resides is x-locked. If the page offset is equal to the free limit
698
 
of the space, adds new extents from above the free limit to the space free
699
 
list, if not free limit == space size. This adding is necessary to make the
700
 
descriptor defined, as they are uninitialized above the free limit.
701
 
@return pointer to the extent descriptor, NULL if the page does not
702
 
exist in the space or if the offset exceeds the free limit */
703
 
UNIV_INLINE
704
 
xdes_t*
705
 
xdes_get_descriptor_with_space_hdr(
706
 
/*===============================*/
707
 
        fsp_header_t*   sp_header,/*!< in/out: space header, x-latched */
708
 
        ulint           space,  /*!< in: space id */
709
 
        ulint           offset, /*!< in: page offset;
710
 
                                if equal to the free limit,
711
 
                                we try to add new extents to
712
 
                                the space free list */
713
 
        mtr_t*          mtr)    /*!< in: mtr handle */
714
 
{
715
 
        ulint   limit;
716
 
        ulint   size;
717
 
        ulint   zip_size;
718
 
        ulint   descr_page_no;
719
 
        page_t* descr_page;
720
 
 
721
 
        ut_ad(mtr);
722
 
        ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
723
 
                                MTR_MEMO_X_LOCK));
724
 
        ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX)
725
 
              || mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
726
 
        ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET);
727
 
        /* Read free limit and space size */
728
 
        limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT);
729
 
        size  = mach_read_from_4(sp_header + FSP_SIZE);
730
 
        zip_size = dict_table_flags_to_zip_size(
731
 
                mach_read_from_4(sp_header + FSP_SPACE_FLAGS));
732
 
 
733
 
        /* If offset is >= size or > limit, return NULL */
734
 
 
735
 
        if ((offset >= size) || (offset > limit)) {
736
 
 
737
 
                return(NULL);
738
 
        }
739
 
 
740
 
        /* If offset is == limit, fill free list of the space. */
741
 
 
742
 
        if (offset == limit) {
743
 
                fsp_fill_free_list(FALSE, space, sp_header, mtr);
744
 
        }
745
 
 
746
 
        descr_page_no = xdes_calc_descriptor_page(zip_size, offset);
747
 
 
748
 
        if (descr_page_no == 0) {
749
 
                /* It is on the space header page */
750
 
 
751
 
                descr_page = page_align(sp_header);
752
 
        } else {
753
 
                buf_block_t*    block;
754
 
 
755
 
                block = buf_page_get(space, zip_size, descr_page_no,
756
 
                                     RW_X_LATCH, mtr);
757
 
                buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
758
 
 
759
 
                descr_page = buf_block_get_frame(block);
760
 
        }
761
 
 
762
 
        return(descr_page + XDES_ARR_OFFSET
763
 
               + XDES_SIZE * xdes_calc_descriptor_index(zip_size, offset));
764
 
}
765
 
 
766
 
/********************************************************************//**
767
 
Gets pointer to a the extent descriptor of a page. The page where the
768
 
extent descriptor resides is x-locked. If the page offset is equal to
769
 
the free limit of the space, adds new extents from above the free limit
770
 
to the space free list, if not free limit == space size. This adding
771
 
is necessary to make the descriptor defined, as they are uninitialized
772
 
above the free limit.
773
 
@return pointer to the extent descriptor, NULL if the page does not
774
 
exist in the space or if the offset exceeds the free limit */
775
 
static
776
 
xdes_t*
777
 
xdes_get_descriptor(
778
 
/*================*/
779
 
        ulint   space,  /*!< in: space id */
780
 
        ulint   zip_size,/*!< in: compressed page size in bytes
781
 
                        or 0 for uncompressed pages */
782
 
        ulint   offset, /*!< in: page offset; if equal to the free limit,
783
 
                        we try to add new extents to the space free list */
784
 
        mtr_t*  mtr)    /*!< in: mtr handle */
785
 
{
786
 
        buf_block_t*    block;
787
 
        fsp_header_t*   sp_header;
788
 
 
789
 
        block = buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
790
 
        buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
791
 
 
792
 
        sp_header = FSP_HEADER_OFFSET + buf_block_get_frame(block);
793
 
        return(xdes_get_descriptor_with_space_hdr(sp_header, space, offset,
794
 
                                                  mtr));
795
 
}
796
 
 
797
 
/********************************************************************//**
798
 
Gets pointer to a the extent descriptor if the file address
799
 
of the descriptor list node is known. The page where the
800
 
extent descriptor resides is x-locked.
801
 
@return pointer to the extent descriptor */
802
 
UNIV_INLINE
803
 
xdes_t*
804
 
xdes_lst_get_descriptor(
805
 
/*====================*/
806
 
        ulint           space,  /*!< in: space id */
807
 
        ulint           zip_size,/*!< in: compressed page size in bytes
808
 
                                or 0 for uncompressed pages */
809
 
        fil_addr_t      lst_node,/*!< in: file address of the list node
810
 
                                contained in the descriptor */
811
 
        mtr_t*          mtr)    /*!< in: mtr handle */
812
 
{
813
 
        xdes_t* descr;
814
 
 
815
 
        ut_ad(mtr);
816
 
        ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
817
 
                                MTR_MEMO_X_LOCK));
818
 
        descr = fut_get_ptr(space, zip_size, lst_node, RW_X_LATCH, mtr)
819
 
                - XDES_FLST_NODE;
820
 
 
821
 
        return(descr);
822
 
}
823
 
 
824
 
/********************************************************************//**
825
 
Returns page offset of the first page in extent described by a descriptor.
826
 
@return offset of the first page in extent */
827
 
UNIV_INLINE
828
 
ulint
829
 
xdes_get_offset(
830
 
/*============*/
831
 
        xdes_t* descr)  /*!< in: extent descriptor */
832
 
{
833
 
        ut_ad(descr);
834
 
 
835
 
        return(page_get_page_no(page_align(descr))
836
 
               + ((page_offset(descr) - XDES_ARR_OFFSET) / XDES_SIZE)
837
 
               * FSP_EXTENT_SIZE);
838
 
}
839
 
#endif /* !UNIV_HOTBACKUP */
840
 
 
841
 
/***********************************************************//**
842
 
Inits a file page whose prior contents should be ignored. */
843
 
static
844
 
void
845
 
fsp_init_file_page_low(
846
 
/*===================*/
847
 
        buf_block_t*    block)  /*!< in: pointer to a page */
848
 
{
849
 
        page_t*         page    = buf_block_get_frame(block);
850
 
        page_zip_des_t* page_zip= buf_block_get_page_zip(block);
851
 
 
852
 
#ifndef UNIV_HOTBACKUP
853
 
        block->check_index_page_at_flush = FALSE;
854
 
#endif /* !UNIV_HOTBACKUP */
855
 
 
856
 
        if (UNIV_LIKELY_NULL(page_zip)) {
857
 
                memset(page, 0, UNIV_PAGE_SIZE);
858
 
                memset(page_zip->data, 0, page_zip_get_size(page_zip));
859
 
                mach_write_to_4(page + FIL_PAGE_OFFSET,
860
 
                                buf_block_get_page_no(block));
861
 
                mach_write_to_4(page
862
 
                                + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
863
 
                                buf_block_get_space(block));
864
 
                memcpy(page_zip->data + FIL_PAGE_OFFSET,
865
 
                       page + FIL_PAGE_OFFSET, 4);
866
 
                memcpy(page_zip->data + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
867
 
                       page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 4);
868
 
                return;
869
 
        }
870
 
 
871
 
        memset(page, 0, UNIV_PAGE_SIZE);
872
 
        mach_write_to_4(page + FIL_PAGE_OFFSET, buf_block_get_page_no(block));
873
 
        mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
874
 
                        buf_block_get_space(block));
875
 
}
876
 
 
877
 
#ifndef UNIV_HOTBACKUP
878
 
/***********************************************************//**
879
 
Inits a file page whose prior contents should be ignored. */
880
 
static
881
 
void
882
 
fsp_init_file_page(
883
 
/*===============*/
884
 
        buf_block_t*    block,  /*!< in: pointer to a page */
885
 
        mtr_t*          mtr)    /*!< in: mtr */
886
 
{
887
 
        fsp_init_file_page_low(block);
888
 
 
889
 
        mlog_write_initial_log_record(buf_block_get_frame(block),
890
 
                                      MLOG_INIT_FILE_PAGE, mtr);
891
 
}
892
 
#endif /* !UNIV_HOTBACKUP */
893
 
 
894
 
/***********************************************************//**
895
 
Parses a redo log record of a file page init.
896
 
@return end of log record or NULL */
897
 
UNIV_INTERN
898
 
byte*
899
 
fsp_parse_init_file_page(
900
 
/*=====================*/
901
 
        byte*           ptr,    /*!< in: buffer */
902
 
        byte*           end_ptr __attribute__((unused)), /*!< in: buffer end */
903
 
        buf_block_t*    block)  /*!< in: block or NULL */
904
 
{
905
 
        ut_ad(ptr && end_ptr);
906
 
 
907
 
        if (block) {
908
 
                fsp_init_file_page_low(block);
909
 
        }
910
 
 
911
 
        return(ptr);
912
 
}
913
 
 
914
 
/**********************************************************************//**
915
 
Initializes the fsp system. */
916
 
UNIV_INTERN
917
 
void
918
 
fsp_init(void)
919
 
/*==========*/
920
 
{
921
 
        /* Does nothing at the moment */
922
 
}
923
 
 
924
 
/**********************************************************************//**
925
 
Writes the space id and compressed page size to a tablespace header.
926
 
This function is used past the buffer pool when we in fil0fil.c create
927
 
a new single-table tablespace. */
928
 
UNIV_INTERN
929
 
void
930
 
fsp_header_init_fields(
931
 
/*===================*/
932
 
        page_t* page,           /*!< in/out: first page in the space */
933
 
        ulint   space_id,       /*!< in: space id */
934
 
        ulint   flags)          /*!< in: tablespace flags (FSP_SPACE_FLAGS):
935
 
                                0, or table->flags if newer than COMPACT */
936
 
{
937
 
        /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for
938
 
        ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and
939
 
        ROW_FORMAT=REDUNDANT (table->flags == 0).  For any other
940
 
        format, the tablespace flags should equal table->flags. */
941
 
        ut_a(flags != DICT_TF_COMPACT);
942
 
 
943
 
        mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_ID + page,
944
 
                        space_id);
945
 
        mach_write_to_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page,
946
 
                        flags);
947
 
}
948
 
 
949
 
#ifndef UNIV_HOTBACKUP
950
 
/**********************************************************************//**
951
 
Initializes the space header of a new created space and creates also the
952
 
insert buffer tree root if space == 0. */
953
 
UNIV_INTERN
954
 
void
955
 
fsp_header_init(
956
 
/*============*/
957
 
        ulint   space,          /*!< in: space id */
958
 
        ulint   size,           /*!< in: current size in blocks */
959
 
        mtr_t*  mtr)            /*!< in: mini-transaction handle */
960
 
{
961
 
        fsp_header_t*   header;
962
 
        buf_block_t*    block;
963
 
        page_t*         page;
964
 
        ulint           flags;
965
 
        ulint           zip_size;
966
 
 
967
 
        ut_ad(mtr);
968
 
 
969
 
        mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
970
 
 
971
 
        zip_size = dict_table_flags_to_zip_size(flags);
972
 
        block = buf_page_create(space, 0, zip_size, mtr);
973
 
        buf_page_get(space, zip_size, 0, RW_X_LATCH, mtr);
974
 
        buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
975
 
 
976
 
        /* The prior contents of the file page should be ignored */
977
 
 
978
 
        fsp_init_file_page(block, mtr);
979
 
        page = buf_block_get_frame(block);
980
 
 
981
 
        mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_TYPE_FSP_HDR,
982
 
                         MLOG_2BYTES, mtr);
983
 
 
984
 
        header = FSP_HEADER_OFFSET + page;
985
 
 
986
 
        mlog_write_ulint(header + FSP_SPACE_ID, space, MLOG_4BYTES, mtr);
987
 
        mlog_write_ulint(header + FSP_NOT_USED, 0, MLOG_4BYTES, mtr);
988
 
 
989
 
        mlog_write_ulint(header + FSP_SIZE, size, MLOG_4BYTES, mtr);
990
 
        mlog_write_ulint(header + FSP_FREE_LIMIT, 0, MLOG_4BYTES, mtr);
991
 
        mlog_write_ulint(header + FSP_SPACE_FLAGS, flags,
992
 
                         MLOG_4BYTES, mtr);
993
 
        mlog_write_ulint(header + FSP_FRAG_N_USED, 0, MLOG_4BYTES, mtr);
994
 
 
995
 
        flst_init(header + FSP_FREE, mtr);
996
 
        flst_init(header + FSP_FREE_FRAG, mtr);
997
 
        flst_init(header + FSP_FULL_FRAG, mtr);
998
 
        flst_init(header + FSP_SEG_INODES_FULL, mtr);
999
 
        flst_init(header + FSP_SEG_INODES_FREE, mtr);
1000
 
 
1001
 
        mlog_write_ull(header + FSP_SEG_ID, 1, mtr);
1002
 
        if (space == 0) {
1003
 
                fsp_fill_free_list(FALSE, space, header, mtr);
1004
 
                btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
1005
 
                           0, 0, DICT_IBUF_ID_MIN + space,
1006
 
                           dict_ind_redundant, mtr);
1007
 
        } else {
1008
 
                fsp_fill_free_list(TRUE, space, header, mtr);
1009
 
        }
1010
 
}
1011
 
#endif /* !UNIV_HOTBACKUP */
1012
 
 
1013
 
/**********************************************************************//**
1014
 
Reads the space id from the first page of a tablespace.
1015
 
@return space id, ULINT UNDEFINED if error */
1016
 
UNIV_INTERN
1017
 
ulint
1018
 
fsp_header_get_space_id(
1019
 
/*====================*/
1020
 
        const page_t*   page)   /*!< in: first page of a tablespace */
1021
 
{
1022
 
        ulint   fsp_id;
1023
 
        ulint   id;
1024
 
 
1025
 
        fsp_id = mach_read_from_4(FSP_HEADER_OFFSET + page + FSP_SPACE_ID);
1026
 
 
1027
 
        id = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
1028
 
 
1029
 
        if (id != fsp_id) {
1030
 
                fprintf(stderr,
1031
 
                        "InnoDB: Error: space id in fsp header %lu,"
1032
 
                        " but in the page header %lu\n",
1033
 
                        (ulong) fsp_id, (ulong) id);
1034
 
 
1035
 
                return(ULINT_UNDEFINED);
1036
 
        }
1037
 
 
1038
 
        return(id);
1039
 
}
1040
 
 
1041
 
/**********************************************************************//**
1042
 
Reads the space flags from the first page of a tablespace.
1043
 
@return flags */
1044
 
UNIV_INTERN
1045
 
ulint
1046
 
fsp_header_get_flags(
1047
 
/*=================*/
1048
 
        const page_t*   page)   /*!< in: first page of a tablespace */
1049
 
{
1050
 
        ut_ad(!page_offset(page));
1051
 
 
1052
 
        return(mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page));
1053
 
}
1054
 
 
1055
 
/**********************************************************************//**
1056
 
Reads the compressed page size from the first page of a tablespace.
1057
 
@return compressed page size in bytes, or 0 if uncompressed */
1058
 
UNIV_INTERN
1059
 
ulint
1060
 
fsp_header_get_zip_size(
1061
 
/*====================*/
1062
 
        const page_t*   page)   /*!< in: first page of a tablespace */
1063
 
{
1064
 
        ulint   flags = fsp_header_get_flags(page);
1065
 
 
1066
 
        return(dict_table_flags_to_zip_size(flags));
1067
 
}
1068
 
 
1069
 
#ifndef UNIV_HOTBACKUP
1070
 
/**********************************************************************//**
1071
 
Increases the space size field of a space. */
1072
 
UNIV_INTERN
1073
 
void
1074
 
fsp_header_inc_size(
1075
 
/*================*/
1076
 
        ulint   space,  /*!< in: space id */
1077
 
        ulint   size_inc,/*!< in: size increment in pages */
1078
 
        mtr_t*  mtr)    /*!< in: mini-transaction handle */
1079
 
{
1080
 
        fsp_header_t*   header;
1081
 
        ulint           size;
1082
 
        ulint           flags;
1083
 
 
1084
 
        ut_ad(mtr);
1085
 
 
1086
 
        mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
1087
 
 
1088
 
        header = fsp_get_space_header(space,
1089
 
                                      dict_table_flags_to_zip_size(flags),
1090
 
                                      mtr);
1091
 
 
1092
 
        size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1093
 
 
1094
 
        mlog_write_ulint(header + FSP_SIZE, size + size_inc, MLOG_4BYTES,
1095
 
                         mtr);
1096
 
}
1097
 
 
1098
 
/**********************************************************************//**
1099
 
Gets the current free limit of the system tablespace.  The free limit
1100
 
means the place of the first page which has never been put to the the
1101
 
free list for allocation.  The space above that address is initialized
1102
 
to zero.  Sets also the global variable log_fsp_current_free_limit.
1103
 
@return free limit in megabytes */
1104
 
UNIV_INTERN
1105
 
ulint
1106
 
fsp_header_get_free_limit(void)
1107
 
/*===========================*/
1108
 
{
1109
 
        fsp_header_t*   header;
1110
 
        ulint           limit;
1111
 
        mtr_t           mtr;
1112
 
 
1113
 
        mtr_start(&mtr);
1114
 
 
1115
 
        mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
1116
 
 
1117
 
        header = fsp_get_space_header(0, 0, &mtr);
1118
 
 
1119
 
        limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, &mtr);
1120
 
 
1121
 
        limit /= ((1024 * 1024) / UNIV_PAGE_SIZE);
1122
 
 
1123
 
        log_fsp_current_free_limit_set_and_checkpoint(limit);
1124
 
 
1125
 
        mtr_commit(&mtr);
1126
 
 
1127
 
        return(limit);
1128
 
}
1129
 
 
1130
 
/**********************************************************************//**
1131
 
Gets the size of the system tablespace from the tablespace header.  If
1132
 
we do not have an auto-extending data file, this should be equal to
1133
 
the size of the data files.  If there is an auto-extending data file,
1134
 
this can be smaller.
1135
 
@return size in pages */
1136
 
UNIV_INTERN
1137
 
ulint
1138
 
fsp_header_get_tablespace_size(void)
1139
 
/*================================*/
1140
 
{
1141
 
        fsp_header_t*   header;
1142
 
        ulint           size;
1143
 
        mtr_t           mtr;
1144
 
 
1145
 
        mtr_start(&mtr);
1146
 
 
1147
 
        mtr_x_lock(fil_space_get_latch(0, NULL), &mtr);
1148
 
 
1149
 
        header = fsp_get_space_header(0, 0, &mtr);
1150
 
 
1151
 
        size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
1152
 
 
1153
 
        mtr_commit(&mtr);
1154
 
 
1155
 
        return(size);
1156
 
}
1157
 
 
1158
 
/***********************************************************************//**
1159
 
Tries to extend a single-table tablespace so that a page would fit in the
1160
 
data file.
1161
 
@return TRUE if success */
1162
 
static
1163
 
ibool
1164
 
fsp_try_extend_data_file_with_pages(
1165
 
/*================================*/
1166
 
        ulint           space,          /*!< in: space */
1167
 
        ulint           page_no,        /*!< in: page number */
1168
 
        fsp_header_t*   header,         /*!< in: space header */
1169
 
        mtr_t*          mtr)            /*!< in: mtr */
1170
 
{
1171
 
        ibool   success;
1172
 
        ulint   actual_size;
1173
 
        ulint   size;
1174
 
 
1175
 
        ut_a(space != 0);
1176
 
 
1177
 
        size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1178
 
 
1179
 
        ut_a(page_no >= size);
1180
 
 
1181
 
        success = fil_extend_space_to_desired_size(&actual_size, space,
1182
 
                                                   page_no + 1);
1183
 
        /* actual_size now has the space size in pages; it may be less than
1184
 
        we wanted if we ran out of disk space */
1185
 
 
1186
 
        mlog_write_ulint(header + FSP_SIZE, actual_size, MLOG_4BYTES, mtr);
1187
 
 
1188
 
        return(success);
1189
 
}
1190
 
 
1191
 
/***********************************************************************//**
1192
 
Tries to extend the last data file of a tablespace if it is auto-extending.
1193
 
@return FALSE if not auto-extending */
1194
 
static
1195
 
ibool
1196
 
fsp_try_extend_data_file(
1197
 
/*=====================*/
1198
 
        ulint*          actual_increase,/*!< out: actual increase in pages, where
1199
 
                                        we measure the tablespace size from
1200
 
                                        what the header field says; it may be
1201
 
                                        the actual file size rounded down to
1202
 
                                        megabyte */
1203
 
        ulint           space,          /*!< in: space */
1204
 
        fsp_header_t*   header,         /*!< in: space header */
1205
 
        mtr_t*          mtr)            /*!< in: mtr */
1206
 
{
1207
 
        ulint   size;
1208
 
        ulint   zip_size;
1209
 
        ulint   new_size;
1210
 
        ulint   old_size;
1211
 
        ulint   size_increase;
1212
 
        ulint   actual_size;
1213
 
        ibool   success;
1214
 
 
1215
 
        *actual_increase = 0;
1216
 
 
1217
 
        if (space == 0 && !srv_auto_extend_last_data_file) {
1218
 
 
1219
 
                /* We print the error message only once to avoid
1220
 
                spamming the error log. Note that we don't need
1221
 
                to reset the flag to FALSE as dealing with this
1222
 
                error requires server restart. */
1223
 
                if (fsp_tbs_full_error_printed == FALSE) {
1224
 
                        fprintf(stderr,
1225
 
                                "InnoDB: Error: Data file(s) ran"
1226
 
                                " out of space.\n"
1227
 
                                "Please add another data file or"
1228
 
                                " use \'autoextend\' for the last"
1229
 
                                " data file.\n");
1230
 
                        fsp_tbs_full_error_printed = TRUE;
1231
 
                }
1232
 
                return(FALSE);
1233
 
        }
1234
 
 
1235
 
        size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1236
 
        zip_size = dict_table_flags_to_zip_size(
1237
 
                mach_read_from_4(header + FSP_SPACE_FLAGS));
1238
 
 
1239
 
        old_size = size;
1240
 
 
1241
 
        if (space == 0) {
1242
 
                if (!srv_last_file_size_max) {
1243
 
                        size_increase = SRV_AUTO_EXTEND_INCREMENT;
1244
 
                } else {
1245
 
                        if (srv_last_file_size_max
1246
 
                            < srv_data_file_sizes[srv_n_data_files - 1]) {
1247
 
 
1248
 
                                fprintf(stderr,
1249
 
                                        "InnoDB: Error: Last data file size"
1250
 
                                        " is %lu, max size allowed %lu\n",
1251
 
                                        (ulong) srv_data_file_sizes[
1252
 
                                                srv_n_data_files - 1],
1253
 
                                        (ulong) srv_last_file_size_max);
1254
 
                        }
1255
 
 
1256
 
                        size_increase = srv_last_file_size_max
1257
 
                                - srv_data_file_sizes[srv_n_data_files - 1];
1258
 
                        if (size_increase > SRV_AUTO_EXTEND_INCREMENT) {
1259
 
                                size_increase = SRV_AUTO_EXTEND_INCREMENT;
1260
 
                        }
1261
 
                }
1262
 
        } else {
1263
 
                /* We extend single-table tablespaces first one extent
1264
 
                at a time, but for bigger tablespaces more. It is not
1265
 
                enough to extend always by one extent, because some
1266
 
                extents are frag page extents. */
1267
 
                ulint   extent_size;    /*!< one megabyte, in pages */
1268
 
 
1269
 
                if (!zip_size) {
1270
 
                        extent_size = FSP_EXTENT_SIZE;
1271
 
                } else {
1272
 
                        extent_size = FSP_EXTENT_SIZE
1273
 
                                * UNIV_PAGE_SIZE / zip_size;
1274
 
                }
1275
 
 
1276
 
                if (size < extent_size) {
1277
 
                        /* Let us first extend the file to extent_size */
1278
 
                        success = fsp_try_extend_data_file_with_pages(
1279
 
                                space, extent_size - 1, header, mtr);
1280
 
                        if (!success) {
1281
 
                                new_size = mtr_read_ulint(header + FSP_SIZE,
1282
 
                                                          MLOG_4BYTES, mtr);
1283
 
 
1284
 
                                *actual_increase = new_size - old_size;
1285
 
 
1286
 
                                return(FALSE);
1287
 
                        }
1288
 
 
1289
 
                        size = extent_size;
1290
 
                }
1291
 
 
1292
 
                if (size < 32 * extent_size) {
1293
 
                        size_increase = extent_size;
1294
 
                } else {
1295
 
                        /* Below in fsp_fill_free_list() we assume
1296
 
                        that we add at most FSP_FREE_ADD extents at
1297
 
                        a time */
1298
 
                        size_increase = FSP_FREE_ADD * extent_size;
1299
 
                }
1300
 
        }
1301
 
 
1302
 
        if (size_increase == 0) {
1303
 
 
1304
 
                return(TRUE);
1305
 
        }
1306
 
 
1307
 
        success = fil_extend_space_to_desired_size(&actual_size, space,
1308
 
                                                   size + size_increase);
1309
 
        /* We ignore any fragments of a full megabyte when storing the size
1310
 
        to the space header */
1311
 
 
1312
 
        if (!zip_size) {
1313
 
                new_size = ut_calc_align_down(actual_size,
1314
 
                                              (1024 * 1024) / UNIV_PAGE_SIZE);
1315
 
        } else {
1316
 
                new_size = ut_calc_align_down(actual_size,
1317
 
                                              (1024 * 1024) / zip_size);
1318
 
        }
1319
 
        mlog_write_ulint(header + FSP_SIZE, new_size, MLOG_4BYTES, mtr);
1320
 
 
1321
 
        *actual_increase = new_size - old_size;
1322
 
 
1323
 
        return(TRUE);
1324
 
}
1325
 
 
1326
 
/**********************************************************************//**
1327
 
Puts new extents to the free list if there are free extents above the free
1328
 
limit. If an extent happens to contain an extent descriptor page, the extent
1329
 
is put to the FSP_FREE_FRAG list with the page marked as used. */
1330
 
static
1331
 
void
1332
 
fsp_fill_free_list(
1333
 
/*===============*/
1334
 
        ibool           init_space,     /*!< in: TRUE if this is a single-table
1335
 
                                        tablespace and we are only initing
1336
 
                                        the tablespace's first extent
1337
 
                                        descriptor page and ibuf bitmap page;
1338
 
                                        then we do not allocate more extents */
1339
 
        ulint           space,          /*!< in: space */
1340
 
        fsp_header_t*   header,         /*!< in/out: space header */
1341
 
        mtr_t*          mtr)            /*!< in: mtr */
1342
 
{
1343
 
        ulint   limit;
1344
 
        ulint   size;
1345
 
        ulint   zip_size;
1346
 
        xdes_t* descr;
1347
 
        ulint   count           = 0;
1348
 
        ulint   frag_n_used;
1349
 
        ulint   actual_increase;
1350
 
        ulint   i;
1351
 
        mtr_t   ibuf_mtr;
1352
 
 
1353
 
        ut_ad(header && mtr);
1354
 
        ut_ad(page_offset(header) == FSP_HEADER_OFFSET);
1355
 
 
1356
 
        /* Check if we can fill free list from above the free list limit */
1357
 
        size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1358
 
        limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES, mtr);
1359
 
 
1360
 
        zip_size = dict_table_flags_to_zip_size(
1361
 
                mach_read_from_4(FSP_SPACE_FLAGS + header));
1362
 
        ut_a(ut_is_2pow(zip_size));
1363
 
        ut_a(zip_size <= UNIV_PAGE_SIZE);
1364
 
        ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
1365
 
 
1366
 
        if (space == 0 && srv_auto_extend_last_data_file
1367
 
            && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1368
 
 
1369
 
                /* Try to increase the last data file size */
1370
 
                fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1371
 
                size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1372
 
        }
1373
 
 
1374
 
        if (space != 0 && !init_space
1375
 
            && size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
1376
 
 
1377
 
                /* Try to increase the .ibd file size */
1378
 
                fsp_try_extend_data_file(&actual_increase, space, header, mtr);
1379
 
                size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1380
 
        }
1381
 
 
1382
 
        i = limit;
1383
 
 
1384
 
        while ((init_space && i < 1)
1385
 
               || ((i + FSP_EXTENT_SIZE <= size) && (count < FSP_FREE_ADD))) {
1386
 
 
1387
 
                ibool   init_xdes;
1388
 
                if (zip_size) {
1389
 
                        init_xdes = ut_2pow_remainder(i, zip_size) == 0;
1390
 
                } else {
1391
 
                        init_xdes = ut_2pow_remainder(i, UNIV_PAGE_SIZE) == 0;
1392
 
                }
1393
 
 
1394
 
                mlog_write_ulint(header + FSP_FREE_LIMIT, i + FSP_EXTENT_SIZE,
1395
 
                                 MLOG_4BYTES, mtr);
1396
 
 
1397
 
                /* Update the free limit info in the log system and make
1398
 
                a checkpoint */
1399
 
                if (space == 0) {
1400
 
                        ut_a(!zip_size);
1401
 
                        log_fsp_current_free_limit_set_and_checkpoint(
1402
 
                                (i + FSP_EXTENT_SIZE)
1403
 
                                / ((1024 * 1024) / UNIV_PAGE_SIZE));
1404
 
                }
1405
 
 
1406
 
                if (UNIV_UNLIKELY(init_xdes)) {
1407
 
 
1408
 
                        buf_block_t*    block;
1409
 
 
1410
 
                        /* We are going to initialize a new descriptor page
1411
 
                        and a new ibuf bitmap page: the prior contents of the
1412
 
                        pages should be ignored. */
1413
 
 
1414
 
                        if (i > 0) {
1415
 
                                block = buf_page_create(
1416
 
                                        space, i, zip_size, mtr);
1417
 
                                buf_page_get(space, zip_size, i,
1418
 
                                             RW_X_LATCH, mtr);
1419
 
                                buf_block_dbg_add_level(block,
1420
 
                                                        SYNC_FSP_PAGE);
1421
 
 
1422
 
                                fsp_init_file_page(block, mtr);
1423
 
                                mlog_write_ulint(buf_block_get_frame(block)
1424
 
                                                 + FIL_PAGE_TYPE,
1425
 
                                                 FIL_PAGE_TYPE_XDES,
1426
 
                                                 MLOG_2BYTES, mtr);
1427
 
                        }
1428
 
 
1429
 
                        /* Initialize the ibuf bitmap page in a separate
1430
 
                        mini-transaction because it is low in the latching
1431
 
                        order, and we must be able to release its latch
1432
 
                        before returning from the fsp routine */
1433
 
 
1434
 
                        mtr_start(&ibuf_mtr);
1435
 
 
1436
 
                        block = buf_page_create(space,
1437
 
                                                    i + FSP_IBUF_BITMAP_OFFSET,
1438
 
                                                    zip_size, &ibuf_mtr);
1439
 
                        buf_page_get(space, zip_size,
1440
 
                                     i + FSP_IBUF_BITMAP_OFFSET,
1441
 
                                     RW_X_LATCH, &ibuf_mtr);
1442
 
                        buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1443
 
 
1444
 
                        fsp_init_file_page(block, &ibuf_mtr);
1445
 
 
1446
 
                        ibuf_bitmap_page_init(block, &ibuf_mtr);
1447
 
 
1448
 
                        mtr_commit(&ibuf_mtr);
1449
 
                }
1450
 
 
1451
 
                descr = xdes_get_descriptor_with_space_hdr(header, space, i,
1452
 
                                                           mtr);
1453
 
                xdes_init(descr, mtr);
1454
 
 
1455
 
#if UNIV_PAGE_SIZE % FSP_EXTENT_SIZE
1456
 
# error "UNIV_PAGE_SIZE % FSP_EXTENT_SIZE != 0"
1457
 
#endif
1458
 
#if PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE
1459
 
# error "PAGE_ZIP_MIN_SIZE % FSP_EXTENT_SIZE != 0"
1460
 
#endif
1461
 
 
1462
 
                if (UNIV_UNLIKELY(init_xdes)) {
1463
 
 
1464
 
                        /* The first page in the extent is a descriptor page
1465
 
                        and the second is an ibuf bitmap page: mark them
1466
 
                        used */
1467
 
 
1468
 
                        xdes_set_bit(descr, XDES_FREE_BIT, 0, FALSE, mtr);
1469
 
                        xdes_set_bit(descr, XDES_FREE_BIT,
1470
 
                                     FSP_IBUF_BITMAP_OFFSET, FALSE, mtr);
1471
 
                        xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1472
 
 
1473
 
                        flst_add_last(header + FSP_FREE_FRAG,
1474
 
                                      descr + XDES_FLST_NODE, mtr);
1475
 
                        frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
1476
 
                                                     MLOG_4BYTES, mtr);
1477
 
                        mlog_write_ulint(header + FSP_FRAG_N_USED,
1478
 
                                         frag_n_used + 2, MLOG_4BYTES, mtr);
1479
 
                } else {
1480
 
                        flst_add_last(header + FSP_FREE,
1481
 
                                      descr + XDES_FLST_NODE, mtr);
1482
 
                        count++;
1483
 
                }
1484
 
 
1485
 
                i += FSP_EXTENT_SIZE;
1486
 
        }
1487
 
}
1488
 
 
1489
 
/**********************************************************************//**
1490
 
Allocates a new free extent.
1491
 
@return extent descriptor, NULL if cannot be allocated */
1492
 
static
1493
 
xdes_t*
1494
 
fsp_alloc_free_extent(
1495
 
/*==================*/
1496
 
        ulint   space,  /*!< in: space id */
1497
 
        ulint   zip_size,/*!< in: compressed page size in bytes
1498
 
                        or 0 for uncompressed pages */
1499
 
        ulint   hint,   /*!< in: hint of which extent would be desirable: any
1500
 
                        page offset in the extent goes; the hint must not
1501
 
                        be > FSP_FREE_LIMIT */
1502
 
        mtr_t*  mtr)    /*!< in: mtr */
1503
 
{
1504
 
        fsp_header_t*   header;
1505
 
        fil_addr_t      first;
1506
 
        xdes_t*         descr;
1507
 
 
1508
 
        ut_ad(mtr);
1509
 
 
1510
 
        header = fsp_get_space_header(space, zip_size, mtr);
1511
 
 
1512
 
        descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1513
 
 
1514
 
        if (descr && (xdes_get_state(descr, mtr) == XDES_FREE)) {
1515
 
                /* Ok, we can take this extent */
1516
 
        } else {
1517
 
                /* Take the first extent in the free list */
1518
 
                first = flst_get_first(header + FSP_FREE, mtr);
1519
 
 
1520
 
                if (fil_addr_is_null(first)) {
1521
 
                        fsp_fill_free_list(FALSE, space, header, mtr);
1522
 
 
1523
 
                        first = flst_get_first(header + FSP_FREE, mtr);
1524
 
                }
1525
 
 
1526
 
                if (fil_addr_is_null(first)) {
1527
 
 
1528
 
                        return(NULL);   /* No free extents left */
1529
 
                }
1530
 
 
1531
 
                descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
1532
 
        }
1533
 
 
1534
 
        flst_remove(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1535
 
 
1536
 
        return(descr);
1537
 
}
1538
 
 
1539
 
/**********************************************************************//**
1540
 
Allocates a single free page from a space. The page is marked as used.
1541
 
@return the page offset, FIL_NULL if no page could be allocated */
1542
 
static
1543
 
ulint
1544
 
fsp_alloc_free_page(
1545
 
/*================*/
1546
 
        ulint   space,  /*!< in: space id */
1547
 
        ulint   zip_size,/*!< in: compressed page size in bytes
1548
 
                        or 0 for uncompressed pages */
1549
 
        ulint   hint,   /*!< in: hint of which page would be desirable */
1550
 
        mtr_t*  mtr)    /*!< in: mtr handle */
1551
 
{
1552
 
        fsp_header_t*   header;
1553
 
        fil_addr_t      first;
1554
 
        xdes_t*         descr;
1555
 
        buf_block_t*    block;
1556
 
        ulint           free;
1557
 
        ulint           frag_n_used;
1558
 
        ulint           page_no;
1559
 
        ulint           space_size;
1560
 
        ibool           success;
1561
 
 
1562
 
        ut_ad(mtr);
1563
 
 
1564
 
        header = fsp_get_space_header(space, zip_size, mtr);
1565
 
 
1566
 
        /* Get the hinted descriptor */
1567
 
        descr = xdes_get_descriptor_with_space_hdr(header, space, hint, mtr);
1568
 
 
1569
 
        if (descr && (xdes_get_state(descr, mtr) == XDES_FREE_FRAG)) {
1570
 
                /* Ok, we can take this extent */
1571
 
        } else {
1572
 
                /* Else take the first extent in free_frag list */
1573
 
                first = flst_get_first(header + FSP_FREE_FRAG, mtr);
1574
 
 
1575
 
                if (fil_addr_is_null(first)) {
1576
 
                        /* There are no partially full fragments: allocate
1577
 
                        a free extent and add it to the FREE_FRAG list. NOTE
1578
 
                        that the allocation may have as a side-effect that an
1579
 
                        extent containing a descriptor page is added to the
1580
 
                        FREE_FRAG list. But we will allocate our page from the
1581
 
                        the free extent anyway. */
1582
 
 
1583
 
                        descr = fsp_alloc_free_extent(space, zip_size,
1584
 
                                                      hint, mtr);
1585
 
 
1586
 
                        if (descr == NULL) {
1587
 
                                /* No free space left */
1588
 
 
1589
 
                                return(FIL_NULL);
1590
 
                        }
1591
 
 
1592
 
                        xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1593
 
                        flst_add_last(header + FSP_FREE_FRAG,
1594
 
                                      descr + XDES_FLST_NODE, mtr);
1595
 
                } else {
1596
 
                        descr = xdes_lst_get_descriptor(space, zip_size,
1597
 
                                                        first, mtr);
1598
 
                }
1599
 
 
1600
 
                /* Reset the hint */
1601
 
                hint = 0;
1602
 
        }
1603
 
 
1604
 
        /* Now we have in descr an extent with at least one free page. Look
1605
 
        for a free page in the extent. */
1606
 
 
1607
 
        free = xdes_find_bit(descr, XDES_FREE_BIT, TRUE,
1608
 
                             hint % FSP_EXTENT_SIZE, mtr);
1609
 
        if (free == ULINT_UNDEFINED) {
1610
 
 
1611
 
                ut_print_buf(stderr, ((byte*)descr) - 500, 1000);
1612
 
                putc('\n', stderr);
1613
 
 
1614
 
                ut_error;
1615
 
        }
1616
 
 
1617
 
        page_no = xdes_get_offset(descr) + free;
1618
 
 
1619
 
        space_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
1620
 
 
1621
 
        if (space_size <= page_no) {
1622
 
                /* It must be that we are extending a single-table tablespace
1623
 
                whose size is still < 64 pages */
1624
 
 
1625
 
                ut_a(space != 0);
1626
 
                if (page_no >= FSP_EXTENT_SIZE) {
1627
 
                        fprintf(stderr,
1628
 
                                "InnoDB: Error: trying to extend a"
1629
 
                                " single-table tablespace %lu\n"
1630
 
                                "InnoDB: by single page(s) though the"
1631
 
                                " space size %lu. Page no %lu.\n",
1632
 
                                (ulong) space, (ulong) space_size,
1633
 
                                (ulong) page_no);
1634
 
                        return(FIL_NULL);
1635
 
                }
1636
 
                success = fsp_try_extend_data_file_with_pages(space, page_no,
1637
 
                                                              header, mtr);
1638
 
                if (!success) {
1639
 
                        /* No disk space left */
1640
 
                        return(FIL_NULL);
1641
 
                }
1642
 
        }
1643
 
 
1644
 
        xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr);
1645
 
 
1646
 
        /* Update the FRAG_N_USED field */
1647
 
        frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1648
 
                                     mtr);
1649
 
        frag_n_used++;
1650
 
        mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
1651
 
                         mtr);
1652
 
        if (xdes_is_full(descr, mtr)) {
1653
 
                /* The fragment is full: move it to another list */
1654
 
                flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1655
 
                            mtr);
1656
 
                xdes_set_state(descr, XDES_FULL_FRAG, mtr);
1657
 
 
1658
 
                flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1659
 
                              mtr);
1660
 
                mlog_write_ulint(header + FSP_FRAG_N_USED,
1661
 
                                 frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
1662
 
                                 mtr);
1663
 
        }
1664
 
 
1665
 
        /* Initialize the allocated page to the buffer pool, so that it can
1666
 
        be obtained immediately with buf_page_get without need for a disk
1667
 
        read. */
1668
 
 
1669
 
        buf_page_create(space, page_no, zip_size, mtr);
1670
 
 
1671
 
        block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
1672
 
        buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1673
 
 
1674
 
        /* Prior contents of the page should be ignored */
1675
 
        fsp_init_file_page(block, mtr);
1676
 
 
1677
 
        return(page_no);
1678
 
}
1679
 
 
1680
 
/**********************************************************************//**
1681
 
Frees a single page of a space. The page is marked as free and clean. */
1682
 
static
1683
 
void
1684
 
fsp_free_page(
1685
 
/*==========*/
1686
 
        ulint   space,  /*!< in: space id */
1687
 
        ulint   zip_size,/*!< in: compressed page size in bytes
1688
 
                        or 0 for uncompressed pages */
1689
 
        ulint   page,   /*!< in: page offset */
1690
 
        mtr_t*  mtr)    /*!< in: mtr handle */
1691
 
{
1692
 
        fsp_header_t*   header;
1693
 
        xdes_t*         descr;
1694
 
        ulint           state;
1695
 
        ulint           frag_n_used;
1696
 
 
1697
 
        ut_ad(mtr);
1698
 
 
1699
 
        /* fprintf(stderr, "Freeing page %lu in space %lu\n", page, space); */
1700
 
 
1701
 
        header = fsp_get_space_header(space, zip_size, mtr);
1702
 
 
1703
 
        descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1704
 
 
1705
 
        state = xdes_get_state(descr, mtr);
1706
 
 
1707
 
        if (state != XDES_FREE_FRAG && state != XDES_FULL_FRAG) {
1708
 
                fprintf(stderr,
1709
 
                        "InnoDB: Error: File space extent descriptor"
1710
 
                        " of page %lu has state %lu\n",
1711
 
                        (ulong) page,
1712
 
                        (ulong) state);
1713
 
                fputs("InnoDB: Dump of descriptor: ", stderr);
1714
 
                ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1715
 
                putc('\n', stderr);
1716
 
 
1717
 
                if (state == XDES_FREE) {
1718
 
                        /* We put here some fault tolerance: if the page
1719
 
                        is already free, return without doing anything! */
1720
 
 
1721
 
                        return;
1722
 
                }
1723
 
 
1724
 
                ut_error;
1725
 
        }
1726
 
 
1727
 
        if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
1728
 
                fprintf(stderr,
1729
 
                        "InnoDB: Error: File space extent descriptor"
1730
 
                        " of page %lu says it is free\n"
1731
 
                        "InnoDB: Dump of descriptor: ", (ulong) page);
1732
 
                ut_print_buf(stderr, ((byte*)descr) - 50, 200);
1733
 
                putc('\n', stderr);
1734
 
 
1735
 
                /* We put here some fault tolerance: if the page
1736
 
                is already free, return without doing anything! */
1737
 
 
1738
 
                return;
1739
 
        }
1740
 
 
1741
 
        xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1742
 
        xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
1743
 
 
1744
 
        frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
1745
 
                                     mtr);
1746
 
        if (state == XDES_FULL_FRAG) {
1747
 
                /* The fragment was full: move it to another list */
1748
 
                flst_remove(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
1749
 
                            mtr);
1750
 
                xdes_set_state(descr, XDES_FREE_FRAG, mtr);
1751
 
                flst_add_last(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1752
 
                              mtr);
1753
 
                mlog_write_ulint(header + FSP_FRAG_N_USED,
1754
 
                                 frag_n_used + FSP_EXTENT_SIZE - 1,
1755
 
                                 MLOG_4BYTES, mtr);
1756
 
        } else {
1757
 
                ut_a(frag_n_used > 0);
1758
 
                mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used - 1,
1759
 
                                 MLOG_4BYTES, mtr);
1760
 
        }
1761
 
 
1762
 
        if (xdes_is_free(descr, mtr)) {
1763
 
                /* The extent has become free: move it to another list */
1764
 
                flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
1765
 
                            mtr);
1766
 
                fsp_free_extent(space, zip_size, page, mtr);
1767
 
        }
1768
 
}
1769
 
 
1770
 
/**********************************************************************//**
1771
 
Returns an extent to the free list of a space. */
1772
 
static
1773
 
void
1774
 
fsp_free_extent(
1775
 
/*============*/
1776
 
        ulint   space,  /*!< in: space id */
1777
 
        ulint   zip_size,/*!< in: compressed page size in bytes
1778
 
                        or 0 for uncompressed pages */
1779
 
        ulint   page,   /*!< in: page offset in the extent */
1780
 
        mtr_t*  mtr)    /*!< in: mtr */
1781
 
{
1782
 
        fsp_header_t*   header;
1783
 
        xdes_t*         descr;
1784
 
 
1785
 
        ut_ad(mtr);
1786
 
 
1787
 
        header = fsp_get_space_header(space, zip_size, mtr);
1788
 
 
1789
 
        descr = xdes_get_descriptor_with_space_hdr(header, space, page, mtr);
1790
 
 
1791
 
        if (xdes_get_state(descr, mtr) == XDES_FREE) {
1792
 
 
1793
 
                ut_print_buf(stderr, (byte*)descr - 500, 1000);
1794
 
                putc('\n', stderr);
1795
 
 
1796
 
                ut_error;
1797
 
        }
1798
 
 
1799
 
        xdes_init(descr, mtr);
1800
 
 
1801
 
        flst_add_last(header + FSP_FREE, descr + XDES_FLST_NODE, mtr);
1802
 
}
1803
 
 
1804
 
/**********************************************************************//**
1805
 
Returns the nth inode slot on an inode page.
1806
 
@return segment inode */
1807
 
UNIV_INLINE
1808
 
fseg_inode_t*
1809
 
fsp_seg_inode_page_get_nth_inode(
1810
 
/*=============================*/
1811
 
        page_t* page,   /*!< in: segment inode page */
1812
 
        ulint   i,      /*!< in: inode index on page */
1813
 
        ulint   zip_size __attribute__((unused)),
1814
 
                        /*!< in: compressed page size, or 0 */
1815
 
        mtr_t*  mtr __attribute__((unused)))
1816
 
                        /*!< in: mini-transaction handle */
1817
 
{
1818
 
        ut_ad(i < FSP_SEG_INODES_PER_PAGE(zip_size));
1819
 
        ut_ad(mtr_memo_contains_page(mtr, page, MTR_MEMO_PAGE_X_FIX));
1820
 
 
1821
 
        return(page + FSEG_ARR_OFFSET + FSEG_INODE_SIZE * i);
1822
 
}
1823
 
 
1824
 
/**********************************************************************//**
1825
 
Looks for a used segment inode on a segment inode page.
1826
 
@return segment inode index, or ULINT_UNDEFINED if not found */
1827
 
static
1828
 
ulint
1829
 
fsp_seg_inode_page_find_used(
1830
 
/*=========================*/
1831
 
        page_t* page,   /*!< in: segment inode page */
1832
 
        ulint   zip_size,/*!< in: compressed page size, or 0 */
1833
 
        mtr_t*  mtr)    /*!< in: mini-transaction handle */
1834
 
{
1835
 
        ulint           i;
1836
 
        fseg_inode_t*   inode;
1837
 
 
1838
 
        for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1839
 
 
1840
 
                inode = fsp_seg_inode_page_get_nth_inode(
1841
 
                        page, i, zip_size, mtr);
1842
 
 
1843
 
                if (mach_read_from_8(inode + FSEG_ID)) {
1844
 
                        /* This is used */
1845
 
 
1846
 
                        ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
1847
 
                              == FSEG_MAGIC_N_VALUE);
1848
 
                        return(i);
1849
 
                }
1850
 
        }
1851
 
 
1852
 
        return(ULINT_UNDEFINED);
1853
 
}
1854
 
 
1855
 
/**********************************************************************//**
1856
 
Looks for an unused segment inode on a segment inode page.
1857
 
@return segment inode index, or ULINT_UNDEFINED if not found */
1858
 
static
1859
 
ulint
1860
 
fsp_seg_inode_page_find_free(
1861
 
/*=========================*/
1862
 
        page_t* page,   /*!< in: segment inode page */
1863
 
        ulint   i,      /*!< in: search forward starting from this index */
1864
 
        ulint   zip_size,/*!< in: compressed page size, or 0 */
1865
 
        mtr_t*  mtr)    /*!< in: mini-transaction handle */
1866
 
{
1867
 
        fseg_inode_t*   inode;
1868
 
 
1869
 
        for (; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1870
 
 
1871
 
                inode = fsp_seg_inode_page_get_nth_inode(
1872
 
                        page, i, zip_size, mtr);
1873
 
 
1874
 
                if (!mach_read_from_8(inode + FSEG_ID)) {
1875
 
                        /* This is unused */
1876
 
 
1877
 
                        return(i);
1878
 
                }
1879
 
 
1880
 
                ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
1881
 
                      == FSEG_MAGIC_N_VALUE);
1882
 
        }
1883
 
 
1884
 
        return(ULINT_UNDEFINED);
1885
 
}
1886
 
 
1887
 
/**********************************************************************//**
1888
 
Allocates a new file segment inode page.
1889
 
@return TRUE if could be allocated */
1890
 
static
1891
 
ibool
1892
 
fsp_alloc_seg_inode_page(
1893
 
/*=====================*/
1894
 
        fsp_header_t*   space_header,   /*!< in: space header */
1895
 
        mtr_t*          mtr)            /*!< in: mini-transaction handle */
1896
 
{
1897
 
        fseg_inode_t*   inode;
1898
 
        buf_block_t*    block;
1899
 
        page_t*         page;
1900
 
        ulint           page_no;
1901
 
        ulint           space;
1902
 
        ulint           zip_size;
1903
 
        ulint           i;
1904
 
 
1905
 
        ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
1906
 
 
1907
 
        space = page_get_space_id(page_align(space_header));
1908
 
        zip_size = dict_table_flags_to_zip_size(
1909
 
                mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1910
 
 
1911
 
        page_no = fsp_alloc_free_page(space, zip_size, 0, mtr);
1912
 
 
1913
 
        if (page_no == FIL_NULL) {
1914
 
 
1915
 
                return(FALSE);
1916
 
        }
1917
 
 
1918
 
        block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
1919
 
        buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1920
 
 
1921
 
        block->check_index_page_at_flush = FALSE;
1922
 
 
1923
 
        page = buf_block_get_frame(block);
1924
 
 
1925
 
        mlog_write_ulint(page + FIL_PAGE_TYPE, FIL_PAGE_INODE,
1926
 
                         MLOG_2BYTES, mtr);
1927
 
 
1928
 
        for (i = 0; i < FSP_SEG_INODES_PER_PAGE(zip_size); i++) {
1929
 
 
1930
 
                inode = fsp_seg_inode_page_get_nth_inode(page, i,
1931
 
                                                         zip_size, mtr);
1932
 
 
1933
 
                mlog_write_ull(inode + FSEG_ID, 0, mtr);
1934
 
        }
1935
 
 
1936
 
        flst_add_last(space_header + FSP_SEG_INODES_FREE,
1937
 
                      page + FSEG_INODE_PAGE_NODE, mtr);
1938
 
        return(TRUE);
1939
 
}
1940
 
 
1941
 
/**********************************************************************//**
1942
 
Allocates a new file segment inode.
1943
 
@return segment inode, or NULL if not enough space */
1944
 
static
1945
 
fseg_inode_t*
1946
 
fsp_alloc_seg_inode(
1947
 
/*================*/
1948
 
        fsp_header_t*   space_header,   /*!< in: space header */
1949
 
        mtr_t*          mtr)            /*!< in: mini-transaction handle */
1950
 
{
1951
 
        ulint           page_no;
1952
 
        buf_block_t*    block;
1953
 
        page_t*         page;
1954
 
        fseg_inode_t*   inode;
1955
 
        ibool           success;
1956
 
        ulint           zip_size;
1957
 
        ulint           n;
1958
 
 
1959
 
        ut_ad(page_offset(space_header) == FSP_HEADER_OFFSET);
1960
 
 
1961
 
        if (flst_get_len(space_header + FSP_SEG_INODES_FREE, mtr) == 0) {
1962
 
                /* Allocate a new segment inode page */
1963
 
 
1964
 
                success = fsp_alloc_seg_inode_page(space_header, mtr);
1965
 
 
1966
 
                if (!success) {
1967
 
 
1968
 
                        return(NULL);
1969
 
                }
1970
 
        }
1971
 
 
1972
 
        page_no = flst_get_first(space_header + FSP_SEG_INODES_FREE, mtr).page;
1973
 
 
1974
 
        zip_size = dict_table_flags_to_zip_size(
1975
 
                mach_read_from_4(FSP_SPACE_FLAGS + space_header));
1976
 
        block = buf_page_get(page_get_space_id(page_align(space_header)),
1977
 
                             zip_size, page_no, RW_X_LATCH, mtr);
1978
 
        buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
1979
 
 
1980
 
        page = buf_block_get_frame(block);
1981
 
 
1982
 
        n = fsp_seg_inode_page_find_free(page, 0, zip_size, mtr);
1983
 
 
1984
 
        ut_a(n != ULINT_UNDEFINED);
1985
 
 
1986
 
        inode = fsp_seg_inode_page_get_nth_inode(page, n, zip_size, mtr);
1987
 
 
1988
 
        if (ULINT_UNDEFINED == fsp_seg_inode_page_find_free(page, n + 1,
1989
 
                                                            zip_size, mtr)) {
1990
 
                /* There are no other unused headers left on the page: move it
1991
 
                to another list */
1992
 
 
1993
 
                flst_remove(space_header + FSP_SEG_INODES_FREE,
1994
 
                            page + FSEG_INODE_PAGE_NODE, mtr);
1995
 
 
1996
 
                flst_add_last(space_header + FSP_SEG_INODES_FULL,
1997
 
                              page + FSEG_INODE_PAGE_NODE, mtr);
1998
 
        }
1999
 
 
2000
 
        ut_ad(!mach_read_from_8(inode + FSEG_ID)
2001
 
              || mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2002
 
        return(inode);
2003
 
}
2004
 
 
2005
 
/**********************************************************************//**
2006
 
Frees a file segment inode. */
2007
 
static
2008
 
void
2009
 
fsp_free_seg_inode(
2010
 
/*===============*/
2011
 
        ulint           space,  /*!< in: space id */
2012
 
        ulint           zip_size,/*!< in: compressed page size in bytes
2013
 
                                or 0 for uncompressed pages */
2014
 
        fseg_inode_t*   inode,  /*!< in: segment inode */
2015
 
        mtr_t*          mtr)    /*!< in: mini-transaction handle */
2016
 
{
2017
 
        page_t*         page;
2018
 
        fsp_header_t*   space_header;
2019
 
 
2020
 
        page = page_align(inode);
2021
 
 
2022
 
        space_header = fsp_get_space_header(space, zip_size, mtr);
2023
 
 
2024
 
        ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2025
 
 
2026
 
        if (ULINT_UNDEFINED
2027
 
            == fsp_seg_inode_page_find_free(page, 0, zip_size, mtr)) {
2028
 
 
2029
 
                /* Move the page to another list */
2030
 
 
2031
 
                flst_remove(space_header + FSP_SEG_INODES_FULL,
2032
 
                            page + FSEG_INODE_PAGE_NODE, mtr);
2033
 
 
2034
 
                flst_add_last(space_header + FSP_SEG_INODES_FREE,
2035
 
                              page + FSEG_INODE_PAGE_NODE, mtr);
2036
 
        }
2037
 
 
2038
 
        mlog_write_ull(inode + FSEG_ID, 0, mtr);
2039
 
        mlog_write_ulint(inode + FSEG_MAGIC_N, 0xfa051ce3, MLOG_4BYTES, mtr);
2040
 
 
2041
 
        if (ULINT_UNDEFINED
2042
 
            == fsp_seg_inode_page_find_used(page, zip_size, mtr)) {
2043
 
 
2044
 
                /* There are no other used headers left on the page: free it */
2045
 
 
2046
 
                flst_remove(space_header + FSP_SEG_INODES_FREE,
2047
 
                            page + FSEG_INODE_PAGE_NODE, mtr);
2048
 
 
2049
 
                fsp_free_page(space, zip_size, page_get_page_no(page), mtr);
2050
 
        }
2051
 
}
2052
 
 
2053
 
/**********************************************************************//**
2054
 
Returns the file segment inode, page x-latched.
2055
 
@return segment inode, page x-latched; NULL if the inode is free */
2056
 
static
2057
 
fseg_inode_t*
2058
 
fseg_inode_try_get(
2059
 
/*===============*/
2060
 
        fseg_header_t*  header, /*!< in: segment header */
2061
 
        ulint           space,  /*!< in: space id */
2062
 
        ulint           zip_size,/*!< in: compressed page size in bytes
2063
 
                                or 0 for uncompressed pages */
2064
 
        mtr_t*          mtr)    /*!< in: mtr handle */
2065
 
{
2066
 
        fil_addr_t      inode_addr;
2067
 
        fseg_inode_t*   inode;
2068
 
 
2069
 
        inode_addr.page = mach_read_from_4(header + FSEG_HDR_PAGE_NO);
2070
 
        inode_addr.boffset = mach_read_from_2(header + FSEG_HDR_OFFSET);
2071
 
        ut_ad(space == mach_read_from_4(header + FSEG_HDR_SPACE));
2072
 
 
2073
 
        inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr);
2074
 
 
2075
 
        if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) {
2076
 
 
2077
 
                inode = NULL;
2078
 
        } else {
2079
 
                ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
2080
 
                      == FSEG_MAGIC_N_VALUE);
2081
 
        }
2082
 
 
2083
 
        return(inode);
2084
 
}
2085
 
 
2086
 
/**********************************************************************//**
2087
 
Returns the file segment inode, page x-latched.
2088
 
@return segment inode, page x-latched */
2089
 
static
2090
 
fseg_inode_t*
2091
 
fseg_inode_get(
2092
 
/*===========*/
2093
 
        fseg_header_t*  header, /*!< in: segment header */
2094
 
        ulint           space,  /*!< in: space id */
2095
 
        ulint           zip_size,/*!< in: compressed page size in bytes
2096
 
                                or 0 for uncompressed pages */
2097
 
        mtr_t*          mtr)    /*!< in: mtr handle */
2098
 
{
2099
 
        fseg_inode_t*   inode
2100
 
                = fseg_inode_try_get(header, space, zip_size, mtr);
2101
 
        ut_a(inode);
2102
 
        return(inode);
2103
 
}
2104
 
 
2105
 
/**********************************************************************//**
2106
 
Gets the page number from the nth fragment page slot.
2107
 
@return page number, FIL_NULL if not in use */
2108
 
UNIV_INLINE
2109
 
ulint
2110
 
fseg_get_nth_frag_page_no(
2111
 
/*======================*/
2112
 
        fseg_inode_t*   inode,  /*!< in: segment inode */
2113
 
        ulint           n,      /*!< in: slot index */
2114
 
        mtr_t*          mtr __attribute__((unused))) /*!< in: mtr handle */
2115
 
{
2116
 
        ut_ad(inode && mtr);
2117
 
        ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
2118
 
        ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2119
 
        ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2120
 
        return(mach_read_from_4(inode + FSEG_FRAG_ARR
2121
 
                                + n * FSEG_FRAG_SLOT_SIZE));
2122
 
}
2123
 
 
2124
 
/**********************************************************************//**
2125
 
Sets the page number in the nth fragment page slot. */
2126
 
UNIV_INLINE
2127
 
void
2128
 
fseg_set_nth_frag_page_no(
2129
 
/*======================*/
2130
 
        fseg_inode_t*   inode,  /*!< in: segment inode */
2131
 
        ulint           n,      /*!< in: slot index */
2132
 
        ulint           page_no,/*!< in: page number to set */
2133
 
        mtr_t*          mtr)    /*!< in: mtr handle */
2134
 
{
2135
 
        ut_ad(inode && mtr);
2136
 
        ut_ad(n < FSEG_FRAG_ARR_N_SLOTS);
2137
 
        ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2138
 
        ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2139
 
 
2140
 
        mlog_write_ulint(inode + FSEG_FRAG_ARR + n * FSEG_FRAG_SLOT_SIZE,
2141
 
                         page_no, MLOG_4BYTES, mtr);
2142
 
}
2143
 
 
2144
 
/**********************************************************************//**
2145
 
Finds a fragment page slot which is free.
2146
 
@return slot index; ULINT_UNDEFINED if none found */
2147
 
static
2148
 
ulint
2149
 
fseg_find_free_frag_page_slot(
2150
 
/*==========================*/
2151
 
        fseg_inode_t*   inode,  /*!< in: segment inode */
2152
 
        mtr_t*          mtr)    /*!< in: mtr handle */
2153
 
{
2154
 
        ulint   i;
2155
 
        ulint   page_no;
2156
 
 
2157
 
        ut_ad(inode && mtr);
2158
 
 
2159
 
        for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2160
 
                page_no = fseg_get_nth_frag_page_no(inode, i, mtr);
2161
 
 
2162
 
                if (page_no == FIL_NULL) {
2163
 
 
2164
 
                        return(i);
2165
 
                }
2166
 
        }
2167
 
 
2168
 
        return(ULINT_UNDEFINED);
2169
 
}
2170
 
 
2171
 
/**********************************************************************//**
2172
 
Finds a fragment page slot which is used and last in the array.
2173
 
@return slot index; ULINT_UNDEFINED if none found */
2174
 
static
2175
 
ulint
2176
 
fseg_find_last_used_frag_page_slot(
2177
 
/*===============================*/
2178
 
        fseg_inode_t*   inode,  /*!< in: segment inode */
2179
 
        mtr_t*          mtr)    /*!< in: mtr handle */
2180
 
{
2181
 
        ulint   i;
2182
 
        ulint   page_no;
2183
 
 
2184
 
        ut_ad(inode && mtr);
2185
 
 
2186
 
        for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2187
 
                page_no = fseg_get_nth_frag_page_no(
2188
 
                        inode, FSEG_FRAG_ARR_N_SLOTS - i - 1, mtr);
2189
 
 
2190
 
                if (page_no != FIL_NULL) {
2191
 
 
2192
 
                        return(FSEG_FRAG_ARR_N_SLOTS - i - 1);
2193
 
                }
2194
 
        }
2195
 
 
2196
 
        return(ULINT_UNDEFINED);
2197
 
}
2198
 
 
2199
 
/**********************************************************************//**
2200
 
Calculates reserved fragment page slots.
2201
 
@return number of fragment pages */
2202
 
static
2203
 
ulint
2204
 
fseg_get_n_frag_pages(
2205
 
/*==================*/
2206
 
        fseg_inode_t*   inode,  /*!< in: segment inode */
2207
 
        mtr_t*          mtr)    /*!< in: mtr handle */
2208
 
{
2209
 
        ulint   i;
2210
 
        ulint   count   = 0;
2211
 
 
2212
 
        ut_ad(inode && mtr);
2213
 
 
2214
 
        for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2215
 
                if (FIL_NULL != fseg_get_nth_frag_page_no(inode, i, mtr)) {
2216
 
                        count++;
2217
 
                }
2218
 
        }
2219
 
 
2220
 
        return(count);
2221
 
}
2222
 
 
2223
 
/**********************************************************************//**
2224
 
Creates a new segment.
2225
 
@return the block where the segment header is placed, x-latched, NULL
2226
 
if could not create segment because of lack of space */
2227
 
UNIV_INTERN
2228
 
buf_block_t*
2229
 
fseg_create_general(
2230
 
/*================*/
2231
 
        ulint   space,  /*!< in: space id */
2232
 
        ulint   page,   /*!< in: page where the segment header is placed: if
2233
 
                        this is != 0, the page must belong to another segment,
2234
 
                        if this is 0, a new page will be allocated and it
2235
 
                        will belong to the created segment */
2236
 
        ulint   byte_offset, /*!< in: byte offset of the created segment header
2237
 
                        on the page */
2238
 
        ibool   has_done_reservation, /*!< in: TRUE if the caller has already
2239
 
                        done the reservation for the pages with
2240
 
                        fsp_reserve_free_extents (at least 2 extents: one for
2241
 
                        the inode and the other for the segment) then there is
2242
 
                        no need to do the check for this individual
2243
 
                        operation */
2244
 
        mtr_t*  mtr)    /*!< in: mtr */
2245
 
{
2246
 
        ulint           flags;
2247
 
        ulint           zip_size;
2248
 
        fsp_header_t*   space_header;
2249
 
        fseg_inode_t*   inode;
2250
 
        ib_id_t         seg_id;
2251
 
        buf_block_t*    block   = 0; /* remove warning */
2252
 
        fseg_header_t*  header  = 0; /* remove warning */
2253
 
        rw_lock_t*      latch;
2254
 
        ibool           success;
2255
 
        ulint           n_reserved;
2256
 
        ulint           i;
2257
 
 
2258
 
        ut_ad(mtr);
2259
 
        ut_ad(byte_offset + FSEG_HEADER_SIZE
2260
 
              <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
2261
 
 
2262
 
        latch = fil_space_get_latch(space, &flags);
2263
 
        zip_size = dict_table_flags_to_zip_size(flags);
2264
 
 
2265
 
        if (page != 0) {
2266
 
                block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
2267
 
                header = byte_offset + buf_block_get_frame(block);
2268
 
        }
2269
 
 
2270
 
        ut_ad(!mutex_own(&kernel_mutex)
2271
 
              || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2272
 
 
2273
 
        mtr_x_lock(latch, mtr);
2274
 
 
2275
 
        if (rw_lock_get_x_lock_count(latch) == 1) {
2276
 
                /* This thread did not own the latch before this call: free
2277
 
                excess pages from the insert buffer free list */
2278
 
 
2279
 
                if (space == IBUF_SPACE_ID) {
2280
 
                        ibuf_free_excess_pages();
2281
 
                }
2282
 
        }
2283
 
 
2284
 
        if (!has_done_reservation) {
2285
 
                success = fsp_reserve_free_extents(&n_reserved, space, 2,
2286
 
                                                   FSP_NORMAL, mtr);
2287
 
                if (!success) {
2288
 
                        return(NULL);
2289
 
                }
2290
 
        }
2291
 
 
2292
 
        space_header = fsp_get_space_header(space, zip_size, mtr);
2293
 
 
2294
 
        inode = fsp_alloc_seg_inode(space_header, mtr);
2295
 
 
2296
 
        if (inode == NULL) {
2297
 
 
2298
 
                goto funct_exit;
2299
 
        }
2300
 
 
2301
 
        /* Read the next segment id from space header and increment the
2302
 
        value in space header */
2303
 
 
2304
 
        seg_id = mach_read_from_8(space_header + FSP_SEG_ID);
2305
 
 
2306
 
        mlog_write_ull(space_header + FSP_SEG_ID, seg_id + 1, mtr);
2307
 
 
2308
 
        mlog_write_ull(inode + FSEG_ID, seg_id, mtr);
2309
 
        mlog_write_ulint(inode + FSEG_NOT_FULL_N_USED, 0, MLOG_4BYTES, mtr);
2310
 
 
2311
 
        flst_init(inode + FSEG_FREE, mtr);
2312
 
        flst_init(inode + FSEG_NOT_FULL, mtr);
2313
 
        flst_init(inode + FSEG_FULL, mtr);
2314
 
 
2315
 
        mlog_write_ulint(inode + FSEG_MAGIC_N, FSEG_MAGIC_N_VALUE,
2316
 
                         MLOG_4BYTES, mtr);
2317
 
        for (i = 0; i < FSEG_FRAG_ARR_N_SLOTS; i++) {
2318
 
                fseg_set_nth_frag_page_no(inode, i, FIL_NULL, mtr);
2319
 
        }
2320
 
 
2321
 
        if (page == 0) {
2322
 
                page = fseg_alloc_free_page_low(space, zip_size,
2323
 
                                                inode, 0, FSP_UP, mtr);
2324
 
 
2325
 
                if (page == FIL_NULL) {
2326
 
 
2327
 
                        fsp_free_seg_inode(space, zip_size, inode, mtr);
2328
 
 
2329
 
                        goto funct_exit;
2330
 
                }
2331
 
 
2332
 
                block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
2333
 
                header = byte_offset + buf_block_get_frame(block);
2334
 
                mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE,
2335
 
                                 FIL_PAGE_TYPE_SYS, MLOG_2BYTES, mtr);
2336
 
        }
2337
 
 
2338
 
        mlog_write_ulint(header + FSEG_HDR_OFFSET,
2339
 
                         page_offset(inode), MLOG_2BYTES, mtr);
2340
 
 
2341
 
        mlog_write_ulint(header + FSEG_HDR_PAGE_NO,
2342
 
                         page_get_page_no(page_align(inode)),
2343
 
                         MLOG_4BYTES, mtr);
2344
 
 
2345
 
        mlog_write_ulint(header + FSEG_HDR_SPACE, space, MLOG_4BYTES, mtr);
2346
 
 
2347
 
funct_exit:
2348
 
        if (!has_done_reservation) {
2349
 
 
2350
 
                fil_space_release_free_extents(space, n_reserved);
2351
 
        }
2352
 
 
2353
 
        return(block);
2354
 
}
2355
 
 
2356
 
/**********************************************************************//**
2357
 
Creates a new segment.
2358
 
@return the block where the segment header is placed, x-latched, NULL
2359
 
if could not create segment because of lack of space */
2360
 
UNIV_INTERN
2361
 
buf_block_t*
2362
 
fseg_create(
2363
 
/*========*/
2364
 
        ulint   space,  /*!< in: space id */
2365
 
        ulint   page,   /*!< in: page where the segment header is placed: if
2366
 
                        this is != 0, the page must belong to another segment,
2367
 
                        if this is 0, a new page will be allocated and it
2368
 
                        will belong to the created segment */
2369
 
        ulint   byte_offset, /*!< in: byte offset of the created segment header
2370
 
                        on the page */
2371
 
        mtr_t*  mtr)    /*!< in: mtr */
2372
 
{
2373
 
        return(fseg_create_general(space, page, byte_offset, FALSE, mtr));
2374
 
}
2375
 
 
2376
 
/**********************************************************************//**
2377
 
Calculates the number of pages reserved by a segment, and how many pages are
2378
 
currently used.
2379
 
@return number of reserved pages */
2380
 
static
2381
 
ulint
2382
 
fseg_n_reserved_pages_low(
2383
 
/*======================*/
2384
 
        fseg_inode_t*   inode,  /*!< in: segment inode */
2385
 
        ulint*          used,   /*!< out: number of pages used (not
2386
 
                                more than reserved) */
2387
 
        mtr_t*          mtr)    /*!< in: mtr handle */
2388
 
{
2389
 
        ulint   ret;
2390
 
 
2391
 
        ut_ad(inode && used && mtr);
2392
 
        ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
2393
 
 
2394
 
        *used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr)
2395
 
                + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr)
2396
 
                + fseg_get_n_frag_pages(inode, mtr);
2397
 
 
2398
 
        ret = fseg_get_n_frag_pages(inode, mtr)
2399
 
                + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FREE, mtr)
2400
 
                + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_NOT_FULL, mtr)
2401
 
                + FSP_EXTENT_SIZE * flst_get_len(inode + FSEG_FULL, mtr);
2402
 
 
2403
 
        return(ret);
2404
 
}
2405
 
 
2406
 
/**********************************************************************//**
2407
 
Calculates the number of pages reserved by a segment, and how many pages are
2408
 
currently used.
2409
 
@return number of reserved pages */
2410
 
UNIV_INTERN
2411
 
ulint
2412
 
fseg_n_reserved_pages(
2413
 
/*==================*/
2414
 
        fseg_header_t*  header, /*!< in: segment header */
2415
 
        ulint*          used,   /*!< out: number of pages used (<= reserved) */
2416
 
        mtr_t*          mtr)    /*!< in: mtr handle */
2417
 
{
2418
 
        ulint           ret;
2419
 
        fseg_inode_t*   inode;
2420
 
        ulint           space;
2421
 
        ulint           flags;
2422
 
        ulint           zip_size;
2423
 
        rw_lock_t*      latch;
2424
 
 
2425
 
        space = page_get_space_id(page_align(header));
2426
 
        latch = fil_space_get_latch(space, &flags);
2427
 
        zip_size = dict_table_flags_to_zip_size(flags);
2428
 
 
2429
 
        ut_ad(!mutex_own(&kernel_mutex)
2430
 
              || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2431
 
 
2432
 
        mtr_x_lock(latch, mtr);
2433
 
 
2434
 
        inode = fseg_inode_get(header, space, zip_size, mtr);
2435
 
 
2436
 
        ret = fseg_n_reserved_pages_low(inode, used, mtr);
2437
 
 
2438
 
        return(ret);
2439
 
}
2440
 
 
2441
 
/*********************************************************************//**
2442
 
Tries to fill the free list of a segment with consecutive free extents.
2443
 
This happens if the segment is big enough to allow extents in the free list,
2444
 
the free list is empty, and the extents can be allocated consecutively from
2445
 
the hint onward. */
2446
 
static
2447
 
void
2448
 
fseg_fill_free_list(
2449
 
/*================*/
2450
 
        fseg_inode_t*   inode,  /*!< in: segment inode */
2451
 
        ulint           space,  /*!< in: space id */
2452
 
        ulint           zip_size,/*!< in: compressed page size in bytes
2453
 
                                or 0 for uncompressed pages */
2454
 
        ulint           hint,   /*!< in: hint which extent would be good as
2455
 
                                the first extent */
2456
 
        mtr_t*          mtr)    /*!< in: mtr */
2457
 
{
2458
 
        xdes_t* descr;
2459
 
        ulint   i;
2460
 
        ib_id_t seg_id;
2461
 
        ulint   reserved;
2462
 
        ulint   used;
2463
 
 
2464
 
        ut_ad(inode && mtr);
2465
 
        ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2466
 
 
2467
 
        reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
2468
 
 
2469
 
        if (reserved < FSEG_FREE_LIST_LIMIT * FSP_EXTENT_SIZE) {
2470
 
 
2471
 
                /* The segment is too small to allow extents in free list */
2472
 
 
2473
 
                return;
2474
 
        }
2475
 
 
2476
 
        if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2477
 
                /* Free list is not empty */
2478
 
 
2479
 
                return;
2480
 
        }
2481
 
 
2482
 
        for (i = 0; i < FSEG_FREE_LIST_MAX_LEN; i++) {
2483
 
                descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2484
 
 
2485
 
                if ((descr == NULL)
2486
 
                    || (XDES_FREE != xdes_get_state(descr, mtr))) {
2487
 
 
2488
 
                        /* We cannot allocate the desired extent: stop */
2489
 
 
2490
 
                        return;
2491
 
                }
2492
 
 
2493
 
                descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2494
 
 
2495
 
                xdes_set_state(descr, XDES_FSEG, mtr);
2496
 
 
2497
 
                seg_id = mach_read_from_8(inode + FSEG_ID);
2498
 
                ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N)
2499
 
                      == FSEG_MAGIC_N_VALUE);
2500
 
                mlog_write_ull(descr + XDES_ID, seg_id, mtr);
2501
 
 
2502
 
                flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2503
 
                hint += FSP_EXTENT_SIZE;
2504
 
        }
2505
 
}
2506
 
 
2507
 
/*********************************************************************//**
2508
 
Allocates a free extent for the segment: looks first in the free list of the
2509
 
segment, then tries to allocate from the space free list. NOTE that the extent
2510
 
returned still resides in the segment free list, it is not yet taken off it!
2511
 
@return allocated extent, still placed in the segment free list, NULL
2512
 
if could not be allocated */
2513
 
static
2514
 
xdes_t*
2515
 
fseg_alloc_free_extent(
2516
 
/*===================*/
2517
 
        fseg_inode_t*   inode,  /*!< in: segment inode */
2518
 
        ulint           space,  /*!< in: space id */
2519
 
        ulint           zip_size,/*!< in: compressed page size in bytes
2520
 
                                or 0 for uncompressed pages */
2521
 
        mtr_t*          mtr)    /*!< in: mtr */
2522
 
{
2523
 
        xdes_t*         descr;
2524
 
        ib_id_t         seg_id;
2525
 
        fil_addr_t      first;
2526
 
 
2527
 
        ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2528
 
        ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
2529
 
 
2530
 
        if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
2531
 
                /* Segment free list is not empty, allocate from it */
2532
 
 
2533
 
                first = flst_get_first(inode + FSEG_FREE, mtr);
2534
 
 
2535
 
                descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
2536
 
        } else {
2537
 
                /* Segment free list was empty, allocate from space */
2538
 
                descr = fsp_alloc_free_extent(space, zip_size, 0, mtr);
2539
 
 
2540
 
                if (descr == NULL) {
2541
 
 
2542
 
                        return(NULL);
2543
 
                }
2544
 
 
2545
 
                seg_id = mach_read_from_8(inode + FSEG_ID);
2546
 
 
2547
 
                xdes_set_state(descr, XDES_FSEG, mtr);
2548
 
                mlog_write_ull(descr + XDES_ID, seg_id, mtr);
2549
 
                flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr);
2550
 
 
2551
 
                /* Try to fill the segment free list */
2552
 
                fseg_fill_free_list(inode, space, zip_size,
2553
 
                                    xdes_get_offset(descr) + FSP_EXTENT_SIZE,
2554
 
                                    mtr);
2555
 
        }
2556
 
 
2557
 
        return(descr);
2558
 
}
2559
 
 
2560
 
/**********************************************************************//**
2561
 
Allocates a single free page from a segment. This function implements
2562
 
the intelligent allocation strategy which tries to minimize file space
2563
 
fragmentation.
2564
 
@return the allocated page number, FIL_NULL if no page could be allocated */
2565
 
static
2566
 
ulint
2567
 
fseg_alloc_free_page_low(
2568
 
/*=====================*/
2569
 
        ulint           space,  /*!< in: space */
2570
 
        ulint           zip_size,/*!< in: compressed page size in bytes
2571
 
                                or 0 for uncompressed pages */
2572
 
        fseg_inode_t*   seg_inode, /*!< in: segment inode */
2573
 
        ulint           hint,   /*!< in: hint of which page would be desirable */
2574
 
        byte            direction, /*!< in: if the new page is needed because
2575
 
                                of an index page split, and records are
2576
 
                                inserted there in order, into which
2577
 
                                direction they go alphabetically: FSP_DOWN,
2578
 
                                FSP_UP, FSP_NO_DIR */
2579
 
        mtr_t*          mtr)    /*!< in: mtr handle */
2580
 
{
2581
 
        fsp_header_t*   space_header;
2582
 
        ulint           space_size;
2583
 
        ib_id_t         seg_id;
2584
 
        ulint           used;
2585
 
        ulint           reserved;
2586
 
        xdes_t*         descr;          /*!< extent of the hinted page */
2587
 
        ulint           ret_page;       /*!< the allocated page offset, FIL_NULL
2588
 
                                        if could not be allocated */
2589
 
        xdes_t*         ret_descr;      /*!< the extent of the allocated page */
2590
 
        ibool           frag_page_allocated = FALSE;
2591
 
        ibool           success;
2592
 
        ulint           n;
2593
 
 
2594
 
        ut_ad(mtr);
2595
 
        ut_ad((direction >= FSP_UP) && (direction <= FSP_NO_DIR));
2596
 
        ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
2597
 
              == FSEG_MAGIC_N_VALUE);
2598
 
        ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
2599
 
        seg_id = mach_read_from_8(seg_inode + FSEG_ID);
2600
 
 
2601
 
        ut_ad(seg_id);
2602
 
 
2603
 
        reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr);
2604
 
 
2605
 
        space_header = fsp_get_space_header(space, zip_size, mtr);
2606
 
 
2607
 
        descr = xdes_get_descriptor_with_space_hdr(space_header, space,
2608
 
                                                   hint, mtr);
2609
 
        if (descr == NULL) {
2610
 
                /* Hint outside space or too high above free limit: reset
2611
 
                hint */
2612
 
                hint = 0;
2613
 
                descr = xdes_get_descriptor(space, zip_size, hint, mtr);
2614
 
        }
2615
 
 
2616
 
        /* In the big if-else below we look for ret_page and ret_descr */
2617
 
        /*-------------------------------------------------------------*/
2618
 
        if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2619
 
            && mach_read_from_8(descr + XDES_ID) == seg_id
2620
 
            && (xdes_get_bit(descr, XDES_FREE_BIT,
2621
 
                             hint % FSP_EXTENT_SIZE, mtr) == TRUE)) {
2622
 
 
2623
 
                /* 1. We can take the hinted page
2624
 
                =================================*/
2625
 
                ret_descr = descr;
2626
 
                ret_page = hint;
2627
 
                /*-----------------------------------------------------------*/
2628
 
        } else if ((xdes_get_state(descr, mtr) == XDES_FREE)
2629
 
                   && ((reserved - used) < reserved / FSEG_FILLFACTOR)
2630
 
                   && (used >= FSEG_FRAG_LIMIT)) {
2631
 
 
2632
 
                /* 2. We allocate the free extent from space and can take
2633
 
                =========================================================
2634
 
                the hinted page
2635
 
                ===============*/
2636
 
                ret_descr = fsp_alloc_free_extent(space, zip_size, hint, mtr);
2637
 
 
2638
 
                ut_a(ret_descr == descr);
2639
 
 
2640
 
                xdes_set_state(ret_descr, XDES_FSEG, mtr);
2641
 
                mlog_write_ull(ret_descr + XDES_ID, seg_id, mtr);
2642
 
                flst_add_last(seg_inode + FSEG_FREE,
2643
 
                              ret_descr + XDES_FLST_NODE, mtr);
2644
 
 
2645
 
                /* Try to fill the segment free list */
2646
 
                fseg_fill_free_list(seg_inode, space, zip_size,
2647
 
                                    hint + FSP_EXTENT_SIZE, mtr);
2648
 
                ret_page = hint;
2649
 
                /*-----------------------------------------------------------*/
2650
 
        } else if ((direction != FSP_NO_DIR)
2651
 
                   && ((reserved - used) < reserved / FSEG_FILLFACTOR)
2652
 
                   && (used >= FSEG_FRAG_LIMIT)
2653
 
                   && (!!(ret_descr
2654
 
                          = fseg_alloc_free_extent(seg_inode,
2655
 
                                                   space, zip_size, mtr)))) {
2656
 
 
2657
 
                /* 3. We take any free extent (which was already assigned above
2658
 
                ===============================================================
2659
 
                in the if-condition to ret_descr) and take the lowest or
2660
 
                ========================================================
2661
 
                highest page in it, depending on the direction
2662
 
                ==============================================*/
2663
 
                ret_page = xdes_get_offset(ret_descr);
2664
 
 
2665
 
                if (direction == FSP_DOWN) {
2666
 
                        ret_page += FSP_EXTENT_SIZE - 1;
2667
 
                }
2668
 
                /*-----------------------------------------------------------*/
2669
 
        } else if ((xdes_get_state(descr, mtr) == XDES_FSEG)
2670
 
                   && mach_read_from_8(descr + XDES_ID) == seg_id
2671
 
                   && (!xdes_is_full(descr, mtr))) {
2672
 
 
2673
 
                /* 4. We can take the page from the same extent as the
2674
 
                ======================================================
2675
 
                hinted page (and the extent already belongs to the
2676
 
                ==================================================
2677
 
                segment)
2678
 
                ========*/
2679
 
                ret_descr = descr;
2680
 
                ret_page = xdes_get_offset(ret_descr)
2681
 
                        + xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2682
 
                                        hint % FSP_EXTENT_SIZE, mtr);
2683
 
                /*-----------------------------------------------------------*/
2684
 
        } else if (reserved - used > 0) {
2685
 
                /* 5. We take any unused page from the segment
2686
 
                ==============================================*/
2687
 
                fil_addr_t      first;
2688
 
 
2689
 
                if (flst_get_len(seg_inode + FSEG_NOT_FULL, mtr) > 0) {
2690
 
                        first = flst_get_first(seg_inode + FSEG_NOT_FULL,
2691
 
                                               mtr);
2692
 
                } else if (flst_get_len(seg_inode + FSEG_FREE, mtr) > 0) {
2693
 
                        first = flst_get_first(seg_inode + FSEG_FREE, mtr);
2694
 
                } else {
2695
 
                        ut_error;
2696
 
                        return(FIL_NULL);
2697
 
                }
2698
 
 
2699
 
                ret_descr = xdes_lst_get_descriptor(space, zip_size,
2700
 
                                                    first, mtr);
2701
 
                ret_page = xdes_get_offset(ret_descr)
2702
 
                        + xdes_find_bit(ret_descr, XDES_FREE_BIT, TRUE,
2703
 
                                        0, mtr);
2704
 
                /*-----------------------------------------------------------*/
2705
 
        } else if (used < FSEG_FRAG_LIMIT) {
2706
 
                /* 6. We allocate an individual page from the space
2707
 
                ===================================================*/
2708
 
                ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr);
2709
 
                ret_descr = NULL;
2710
 
 
2711
 
                frag_page_allocated = TRUE;
2712
 
 
2713
 
                if (ret_page != FIL_NULL) {
2714
 
                        /* Put the page in the fragment page array of the
2715
 
                        segment */
2716
 
                        n = fseg_find_free_frag_page_slot(seg_inode, mtr);
2717
 
                        ut_a(n != FIL_NULL);
2718
 
 
2719
 
                        fseg_set_nth_frag_page_no(seg_inode, n, ret_page,
2720
 
                                                  mtr);
2721
 
                }
2722
 
                /*-----------------------------------------------------------*/
2723
 
        } else {
2724
 
                /* 7. We allocate a new extent and take its first page
2725
 
                ======================================================*/
2726
 
                ret_descr = fseg_alloc_free_extent(seg_inode,
2727
 
                                                   space, zip_size, mtr);
2728
 
 
2729
 
                if (ret_descr == NULL) {
2730
 
                        ret_page = FIL_NULL;
2731
 
                } else {
2732
 
                        ret_page = xdes_get_offset(ret_descr);
2733
 
                }
2734
 
        }
2735
 
 
2736
 
        if (ret_page == FIL_NULL) {
2737
 
                /* Page could not be allocated */
2738
 
 
2739
 
                return(FIL_NULL);
2740
 
        }
2741
 
 
2742
 
        if (space != 0) {
2743
 
                space_size = fil_space_get_size(space);
2744
 
 
2745
 
                if (space_size <= ret_page) {
2746
 
                        /* It must be that we are extending a single-table
2747
 
                        tablespace whose size is still < 64 pages */
2748
 
 
2749
 
                        if (ret_page >= FSP_EXTENT_SIZE) {
2750
 
                                fprintf(stderr,
2751
 
                                        "InnoDB: Error (2): trying to extend"
2752
 
                                        " a single-table tablespace %lu\n"
2753
 
                                        "InnoDB: by single page(s) though"
2754
 
                                        " the space size %lu. Page no %lu.\n",
2755
 
                                        (ulong) space, (ulong) space_size,
2756
 
                                        (ulong) ret_page);
2757
 
                                return(FIL_NULL);
2758
 
                        }
2759
 
 
2760
 
                        success = fsp_try_extend_data_file_with_pages(
2761
 
                                space, ret_page, space_header, mtr);
2762
 
                        if (!success) {
2763
 
                                /* No disk space left */
2764
 
                                return(FIL_NULL);
2765
 
                        }
2766
 
                }
2767
 
        }
2768
 
 
2769
 
        if (!frag_page_allocated) {
2770
 
                /* Initialize the allocated page to buffer pool, so that it
2771
 
                can be obtained immediately with buf_page_get without need
2772
 
                for a disk read */
2773
 
                buf_block_t*    block;
2774
 
                ulint           zip_size = dict_table_flags_to_zip_size(
2775
 
                        mach_read_from_4(FSP_SPACE_FLAGS + space_header));
2776
 
 
2777
 
                block = buf_page_create(space, ret_page, zip_size, mtr);
2778
 
                buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
2779
 
 
2780
 
                if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size,
2781
 
                                                        ret_page, RW_X_LATCH,
2782
 
                                                        mtr))) {
2783
 
                        ut_error;
2784
 
                }
2785
 
 
2786
 
                /* The prior contents of the page should be ignored */
2787
 
                fsp_init_file_page(block, mtr);
2788
 
 
2789
 
                /* At this point we know the extent and the page offset.
2790
 
                The extent is still in the appropriate list (FSEG_NOT_FULL
2791
 
                or FSEG_FREE), and the page is not yet marked as used. */
2792
 
 
2793
 
                ut_ad(xdes_get_descriptor(space, zip_size, ret_page, mtr)
2794
 
                      == ret_descr);
2795
 
                ut_ad(xdes_get_bit(ret_descr, XDES_FREE_BIT,
2796
 
                                   ret_page % FSP_EXTENT_SIZE, mtr) == TRUE);
2797
 
 
2798
 
                fseg_mark_page_used(seg_inode, space, zip_size, ret_page, mtr);
2799
 
        }
2800
 
 
2801
 
        buf_reset_check_index_page_at_flush(space, ret_page);
2802
 
 
2803
 
        return(ret_page);
2804
 
}
2805
 
 
2806
 
/**********************************************************************//**
2807
 
Allocates a single free page from a segment. This function implements
2808
 
the intelligent allocation strategy which tries to minimize file space
2809
 
fragmentation.
2810
 
@return allocated page offset, FIL_NULL if no page could be allocated */
2811
 
UNIV_INTERN
2812
 
ulint
2813
 
fseg_alloc_free_page_general(
2814
 
/*=========================*/
2815
 
        fseg_header_t*  seg_header,/*!< in: segment header */
2816
 
        ulint           hint,   /*!< in: hint of which page would be desirable */
2817
 
        byte            direction,/*!< in: if the new page is needed because
2818
 
                                of an index page split, and records are
2819
 
                                inserted there in order, into which
2820
 
                                direction they go alphabetically: FSP_DOWN,
2821
 
                                FSP_UP, FSP_NO_DIR */
2822
 
        ibool           has_done_reservation, /*!< in: TRUE if the caller has
2823
 
                                already done the reservation for the page
2824
 
                                with fsp_reserve_free_extents, then there
2825
 
                                is no need to do the check for this individual
2826
 
                                page */
2827
 
        mtr_t*          mtr)    /*!< in: mtr handle */
2828
 
{
2829
 
        fseg_inode_t*   inode;
2830
 
        ulint           space;
2831
 
        ulint           flags;
2832
 
        ulint           zip_size;
2833
 
        rw_lock_t*      latch;
2834
 
        ibool           success;
2835
 
        ulint           page_no;
2836
 
        ulint           n_reserved;
2837
 
 
2838
 
        space = page_get_space_id(page_align(seg_header));
2839
 
 
2840
 
        latch = fil_space_get_latch(space, &flags);
2841
 
 
2842
 
        zip_size = dict_table_flags_to_zip_size(flags);
2843
 
 
2844
 
        ut_ad(!mutex_own(&kernel_mutex)
2845
 
              || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2846
 
 
2847
 
        mtr_x_lock(latch, mtr);
2848
 
 
2849
 
        if (rw_lock_get_x_lock_count(latch) == 1) {
2850
 
                /* This thread did not own the latch before this call: free
2851
 
                excess pages from the insert buffer free list */
2852
 
 
2853
 
                if (space == IBUF_SPACE_ID) {
2854
 
                        ibuf_free_excess_pages();
2855
 
                }
2856
 
        }
2857
 
 
2858
 
        inode = fseg_inode_get(seg_header, space, zip_size, mtr);
2859
 
 
2860
 
        if (!has_done_reservation) {
2861
 
                success = fsp_reserve_free_extents(&n_reserved, space, 2,
2862
 
                                                   FSP_NORMAL, mtr);
2863
 
                if (!success) {
2864
 
                        return(FIL_NULL);
2865
 
                }
2866
 
        }
2867
 
 
2868
 
        page_no = fseg_alloc_free_page_low(space, zip_size,
2869
 
                                           inode, hint, direction, mtr);
2870
 
        if (!has_done_reservation) {
2871
 
                fil_space_release_free_extents(space, n_reserved);
2872
 
        }
2873
 
 
2874
 
        return(page_no);
2875
 
}
2876
 
 
2877
 
/**********************************************************************//**
2878
 
Allocates a single free page from a segment. This function implements
2879
 
the intelligent allocation strategy which tries to minimize file space
2880
 
fragmentation.
2881
 
@return allocated page offset, FIL_NULL if no page could be allocated */
2882
 
UNIV_INTERN
2883
 
ulint
2884
 
fseg_alloc_free_page(
2885
 
/*=================*/
2886
 
        fseg_header_t*  seg_header,/*!< in: segment header */
2887
 
        ulint           hint,   /*!< in: hint of which page would be desirable */
2888
 
        byte            direction,/*!< in: if the new page is needed because
2889
 
                                of an index page split, and records are
2890
 
                                inserted there in order, into which
2891
 
                                direction they go alphabetically: FSP_DOWN,
2892
 
                                FSP_UP, FSP_NO_DIR */
2893
 
        mtr_t*          mtr)    /*!< in: mtr handle */
2894
 
{
2895
 
        return(fseg_alloc_free_page_general(seg_header, hint, direction,
2896
 
                                            FALSE, mtr));
2897
 
}
2898
 
 
2899
 
/**********************************************************************//**
2900
 
Checks that we have at least 2 frag pages free in the first extent of a
2901
 
single-table tablespace, and they are also physically initialized to the data
2902
 
file. That is we have already extended the data file so that those pages are
2903
 
inside the data file. If not, this function extends the tablespace with
2904
 
pages.
2905
 
@return TRUE if there were >= 3 free pages, or we were able to extend */
2906
 
static
2907
 
ibool
2908
 
fsp_reserve_free_pages(
2909
 
/*===================*/
2910
 
        ulint           space,          /*!< in: space id, must be != 0 */
2911
 
        fsp_header_t*   space_header,   /*!< in: header of that space,
2912
 
                                        x-latched */
2913
 
        ulint           size,           /*!< in: size of the tablespace in pages,
2914
 
                                        must be < FSP_EXTENT_SIZE / 2 */
2915
 
        mtr_t*          mtr)            /*!< in: mtr */
2916
 
{
2917
 
        xdes_t* descr;
2918
 
        ulint   n_used;
2919
 
 
2920
 
        ut_a(space != 0);
2921
 
        ut_a(size < FSP_EXTENT_SIZE / 2);
2922
 
 
2923
 
        descr = xdes_get_descriptor_with_space_hdr(space_header, space, 0,
2924
 
                                                   mtr);
2925
 
        n_used = xdes_get_n_used(descr, mtr);
2926
 
 
2927
 
        ut_a(n_used <= size);
2928
 
 
2929
 
        if (size >= n_used + 2) {
2930
 
 
2931
 
                return(TRUE);
2932
 
        }
2933
 
 
2934
 
        return(fsp_try_extend_data_file_with_pages(space, n_used + 1,
2935
 
                                                   space_header, mtr));
2936
 
}
2937
 
 
2938
 
/**********************************************************************//**
2939
 
Reserves free pages from a tablespace. All mini-transactions which may
2940
 
use several pages from the tablespace should call this function beforehand
2941
 
and reserve enough free extents so that they certainly will be able
2942
 
to do their operation, like a B-tree page split, fully. Reservations
2943
 
must be released with function fil_space_release_free_extents!
2944
 
 
2945
 
The alloc_type below has the following meaning: FSP_NORMAL means an
2946
 
operation which will probably result in more space usage, like an
2947
 
insert in a B-tree; FSP_UNDO means allocation to undo logs: if we are
2948
 
deleting rows, then this allocation will in the long run result in
2949
 
less space usage (after a purge); FSP_CLEANING means allocation done
2950
 
in a physical record delete (like in a purge) or other cleaning operation
2951
 
which will result in less space usage in the long run. We prefer the latter
2952
 
two types of allocation: when space is scarce, FSP_NORMAL allocations
2953
 
will not succeed, but the latter two allocations will succeed, if possible.
2954
 
The purpose is to avoid dead end where the database is full but the
2955
 
user cannot free any space because these freeing operations temporarily
2956
 
reserve some space.
2957
 
 
2958
 
Single-table tablespaces whose size is < 32 pages are a special case. In this
2959
 
function we would liberally reserve several 64 page extents for every page
2960
 
split or merge in a B-tree. But we do not want to waste disk space if the table
2961
 
only occupies < 32 pages. That is why we apply different rules in that special
2962
 
case, just ensuring that there are 3 free pages available.
2963
 
@return TRUE if we were able to make the reservation */
2964
 
UNIV_INTERN
2965
 
ibool
2966
 
fsp_reserve_free_extents(
2967
 
/*=====================*/
2968
 
        ulint*  n_reserved,/*!< out: number of extents actually reserved; if we
2969
 
                        return TRUE and the tablespace size is < 64 pages,
2970
 
                        then this can be 0, otherwise it is n_ext */
2971
 
        ulint   space,  /*!< in: space id */
2972
 
        ulint   n_ext,  /*!< in: number of extents to reserve */
2973
 
        ulint   alloc_type,/*!< in: FSP_NORMAL, FSP_UNDO, or FSP_CLEANING */
2974
 
        mtr_t*  mtr)    /*!< in: mtr */
2975
 
{
2976
 
        fsp_header_t*   space_header;
2977
 
        rw_lock_t*      latch;
2978
 
        ulint           n_free_list_ext;
2979
 
        ulint           free_limit;
2980
 
        ulint           size;
2981
 
        ulint           flags;
2982
 
        ulint           zip_size;
2983
 
        ulint           n_free;
2984
 
        ulint           n_free_up;
2985
 
        ulint           reserve;
2986
 
        ibool           success;
2987
 
        ulint           n_pages_added;
2988
 
 
2989
 
        ut_ad(mtr);
2990
 
        *n_reserved = n_ext;
2991
 
 
2992
 
        latch = fil_space_get_latch(space, &flags);
2993
 
        zip_size = dict_table_flags_to_zip_size(flags);
2994
 
 
2995
 
        ut_ad(!mutex_own(&kernel_mutex)
2996
 
              || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
2997
 
 
2998
 
        mtr_x_lock(latch, mtr);
2999
 
 
3000
 
        space_header = fsp_get_space_header(space, zip_size, mtr);
3001
 
try_again:
3002
 
        size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, mtr);
3003
 
 
3004
 
        if (size < FSP_EXTENT_SIZE / 2) {
3005
 
                /* Use different rules for small single-table tablespaces */
3006
 
                *n_reserved = 0;
3007
 
                return(fsp_reserve_free_pages(space, space_header, size, mtr));
3008
 
        }
3009
 
 
3010
 
        n_free_list_ext = flst_get_len(space_header + FSP_FREE, mtr);
3011
 
 
3012
 
        free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
3013
 
                                    MLOG_4BYTES, mtr);
3014
 
 
3015
 
        /* Below we play safe when counting free extents above the free limit:
3016
 
        some of them will contain extent descriptor pages, and therefore
3017
 
        will not be free extents */
3018
 
 
3019
 
        n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
3020
 
 
3021
 
        if (n_free_up > 0) {
3022
 
                n_free_up--;
3023
 
                if (!zip_size) {
3024
 
                        n_free_up -= n_free_up
3025
 
                                / (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
3026
 
                } else {
3027
 
                        n_free_up -= n_free_up
3028
 
                                / (zip_size / FSP_EXTENT_SIZE);
3029
 
                }
3030
 
        }
3031
 
 
3032
 
        n_free = n_free_list_ext + n_free_up;
3033
 
 
3034
 
        if (alloc_type == FSP_NORMAL) {
3035
 
                /* We reserve 1 extent + 0.5 % of the space size to undo logs
3036
 
                and 1 extent + 0.5 % to cleaning operations; NOTE: this source
3037
 
                code is duplicated in the function below! */
3038
 
 
3039
 
                reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
3040
 
 
3041
 
                if (n_free <= reserve + n_ext) {
3042
 
 
3043
 
                        goto try_to_extend;
3044
 
                }
3045
 
        } else if (alloc_type == FSP_UNDO) {
3046
 
                /* We reserve 0.5 % of the space size to cleaning operations */
3047
 
 
3048
 
                reserve = 1 + ((size / FSP_EXTENT_SIZE) * 1) / 200;
3049
 
 
3050
 
                if (n_free <= reserve + n_ext) {
3051
 
 
3052
 
                        goto try_to_extend;
3053
 
                }
3054
 
        } else {
3055
 
                ut_a(alloc_type == FSP_CLEANING);
3056
 
        }
3057
 
 
3058
 
        success = fil_space_reserve_free_extents(space, n_free, n_ext);
3059
 
 
3060
 
        if (success) {
3061
 
                return(TRUE);
3062
 
        }
3063
 
try_to_extend:
3064
 
        success = fsp_try_extend_data_file(&n_pages_added, space,
3065
 
                                           space_header, mtr);
3066
 
        if (success && n_pages_added > 0) {
3067
 
 
3068
 
                goto try_again;
3069
 
        }
3070
 
 
3071
 
        return(FALSE);
3072
 
}
3073
 
 
3074
 
/**********************************************************************//**
3075
 
This function should be used to get information on how much we still
3076
 
will be able to insert new data to the database without running out the
3077
 
tablespace. Only free extents are taken into account and we also subtract
3078
 
the safety margin required by the above function fsp_reserve_free_extents.
3079
 
@return available space in kB */
3080
 
UNIV_INTERN
3081
 
ullint
3082
 
fsp_get_available_space_in_free_extents(
3083
 
/*====================================*/
3084
 
        ulint   space)  /*!< in: space id */
3085
 
{
3086
 
        fsp_header_t*   space_header;
3087
 
        ulint           n_free_list_ext;
3088
 
        ulint           free_limit;
3089
 
        ulint           size;
3090
 
        ulint           flags;
3091
 
        ulint           zip_size;
3092
 
        ulint           n_free;
3093
 
        ulint           n_free_up;
3094
 
        ulint           reserve;
3095
 
        rw_lock_t*      latch;
3096
 
        mtr_t           mtr;
3097
 
 
3098
 
        ut_ad(!mutex_own(&kernel_mutex));
3099
 
 
3100
 
        mtr_start(&mtr);
3101
 
 
3102
 
        latch = fil_space_get_latch(space, &flags);
3103
 
        zip_size = dict_table_flags_to_zip_size(flags);
3104
 
 
3105
 
        mtr_x_lock(latch, &mtr);
3106
 
 
3107
 
        space_header = fsp_get_space_header(space, zip_size, &mtr);
3108
 
 
3109
 
        size = mtr_read_ulint(space_header + FSP_SIZE, MLOG_4BYTES, &mtr);
3110
 
 
3111
 
        n_free_list_ext = flst_get_len(space_header + FSP_FREE, &mtr);
3112
 
 
3113
 
        free_limit = mtr_read_ulint(space_header + FSP_FREE_LIMIT,
3114
 
                                    MLOG_4BYTES, &mtr);
3115
 
        mtr_commit(&mtr);
3116
 
 
3117
 
        if (size < FSP_EXTENT_SIZE) {
3118
 
                ut_a(space != 0);       /* This must be a single-table
3119
 
                                        tablespace */
3120
 
 
3121
 
                return(0);              /* TODO: count free frag pages and
3122
 
                                        return a value based on that */
3123
 
        }
3124
 
 
3125
 
        /* Below we play safe when counting free extents above the free limit:
3126
 
        some of them will contain extent descriptor pages, and therefore
3127
 
        will not be free extents */
3128
 
 
3129
 
        n_free_up = (size - free_limit) / FSP_EXTENT_SIZE;
3130
 
 
3131
 
        if (n_free_up > 0) {
3132
 
                n_free_up--;
3133
 
                if (!zip_size) {
3134
 
                        n_free_up -= n_free_up
3135
 
                                / (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE);
3136
 
                } else {
3137
 
                        n_free_up -= n_free_up
3138
 
                                / (zip_size / FSP_EXTENT_SIZE);
3139
 
                }
3140
 
        }
3141
 
 
3142
 
        n_free = n_free_list_ext + n_free_up;
3143
 
 
3144
 
        /* We reserve 1 extent + 0.5 % of the space size to undo logs
3145
 
        and 1 extent + 0.5 % to cleaning operations; NOTE: this source
3146
 
        code is duplicated in the function above! */
3147
 
 
3148
 
        reserve = 2 + ((size / FSP_EXTENT_SIZE) * 2) / 200;
3149
 
 
3150
 
        if (reserve > n_free) {
3151
 
                return(0);
3152
 
        }
3153
 
 
3154
 
        if (!zip_size) {
3155
 
                return((ullint) (n_free - reserve)
3156
 
                       * FSP_EXTENT_SIZE
3157
 
                       * (UNIV_PAGE_SIZE / 1024));
3158
 
        } else {
3159
 
                return((ullint) (n_free - reserve)
3160
 
                       * FSP_EXTENT_SIZE
3161
 
                       * (zip_size / 1024));
3162
 
        }
3163
 
}
3164
 
 
3165
 
/********************************************************************//**
3166
 
Marks a page used. The page must reside within the extents of the given
3167
 
segment. */
3168
 
static
3169
 
void
3170
 
fseg_mark_page_used(
3171
 
/*================*/
3172
 
        fseg_inode_t*   seg_inode,/*!< in: segment inode */
3173
 
        ulint           space,  /*!< in: space id */
3174
 
        ulint           zip_size,/*!< in: compressed page size in bytes
3175
 
                                or 0 for uncompressed pages */
3176
 
        ulint           page,   /*!< in: page offset */
3177
 
        mtr_t*          mtr)    /*!< in: mtr */
3178
 
{
3179
 
        xdes_t* descr;
3180
 
        ulint   not_full_n_used;
3181
 
 
3182
 
        ut_ad(seg_inode && mtr);
3183
 
        ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
3184
 
        ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3185
 
              == FSEG_MAGIC_N_VALUE);
3186
 
 
3187
 
        descr = xdes_get_descriptor(space, zip_size, page, mtr);
3188
 
 
3189
 
        ut_ad(mtr_read_ulint(seg_inode + FSEG_ID, MLOG_4BYTES, mtr)
3190
 
              == mtr_read_ulint(descr + XDES_ID, MLOG_4BYTES, mtr));
3191
 
 
3192
 
        if (xdes_is_free(descr, mtr)) {
3193
 
                /* We move the extent from the free list to the
3194
 
                NOT_FULL list */
3195
 
                flst_remove(seg_inode + FSEG_FREE, descr + XDES_FLST_NODE,
3196
 
                            mtr);
3197
 
                flst_add_last(seg_inode + FSEG_NOT_FULL,
3198
 
                              descr + XDES_FLST_NODE, mtr);
3199
 
        }
3200
 
 
3201
 
        ut_ad(xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)
3202
 
              == TRUE);
3203
 
        /* We mark the page as used */
3204
 
        xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, FALSE, mtr);
3205
 
 
3206
 
        not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3207
 
                                         MLOG_4BYTES, mtr);
3208
 
        not_full_n_used++;
3209
 
        mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED, not_full_n_used,
3210
 
                         MLOG_4BYTES, mtr);
3211
 
        if (xdes_is_full(descr, mtr)) {
3212
 
                /* We move the extent from the NOT_FULL list to the
3213
 
                FULL list */
3214
 
                flst_remove(seg_inode + FSEG_NOT_FULL,
3215
 
                            descr + XDES_FLST_NODE, mtr);
3216
 
                flst_add_last(seg_inode + FSEG_FULL,
3217
 
                              descr + XDES_FLST_NODE, mtr);
3218
 
 
3219
 
                mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3220
 
                                 not_full_n_used - FSP_EXTENT_SIZE,
3221
 
                                 MLOG_4BYTES, mtr);
3222
 
        }
3223
 
}
3224
 
 
3225
 
/**********************************************************************//**
3226
 
Frees a single page of a segment. */
3227
 
static
3228
 
void
3229
 
fseg_free_page_low(
3230
 
/*===============*/
3231
 
        fseg_inode_t*   seg_inode, /*!< in: segment inode */
3232
 
        ulint           space,  /*!< in: space id */
3233
 
        ulint           zip_size,/*!< in: compressed page size in bytes
3234
 
                                or 0 for uncompressed pages */
3235
 
        ulint           page,   /*!< in: page offset */
3236
 
        mtr_t*          mtr)    /*!< in: mtr handle */
3237
 
{
3238
 
        xdes_t* descr;
3239
 
        ulint   not_full_n_used;
3240
 
        ulint   state;
3241
 
        ib_id_t descr_id;
3242
 
        ib_id_t seg_id;
3243
 
        ulint   i;
3244
 
 
3245
 
        ut_ad(seg_inode && mtr);
3246
 
        ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3247
 
              == FSEG_MAGIC_N_VALUE);
3248
 
        ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE));
3249
 
 
3250
 
        /* Drop search system page hash index if the page is found in
3251
 
        the pool and is hashed */
3252
 
 
3253
 
        btr_search_drop_page_hash_when_freed(space, zip_size, page);
3254
 
 
3255
 
        descr = xdes_get_descriptor(space, zip_size, page, mtr);
3256
 
 
3257
 
        ut_a(descr);
3258
 
        if (xdes_get_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, mtr)) {
3259
 
                fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3260
 
                      stderr);
3261
 
                ut_print_buf(stderr, descr, 40);
3262
 
 
3263
 
                fprintf(stderr, "\n"
3264
 
                        "InnoDB: Serious error! InnoDB is trying to"
3265
 
                        " free page %lu\n"
3266
 
                        "InnoDB: though it is already marked as free"
3267
 
                        " in the tablespace!\n"
3268
 
                        "InnoDB: The tablespace free space info is corrupt.\n"
3269
 
                        "InnoDB: You may need to dump your"
3270
 
                        " InnoDB tables and recreate the whole\n"
3271
 
                        "InnoDB: database!\n", (ulong) page);
3272
 
crash:
3273
 
                fputs("InnoDB: Please refer to\n"
3274
 
                      "InnoDB: " REFMAN "forcing-recovery.html\n"
3275
 
                      "InnoDB: about forcing recovery.\n", stderr);
3276
 
                ut_error;
3277
 
        }
3278
 
 
3279
 
        state = xdes_get_state(descr, mtr);
3280
 
 
3281
 
        if (state != XDES_FSEG) {
3282
 
                /* The page is in the fragment pages of the segment */
3283
 
 
3284
 
                for (i = 0;; i++) {
3285
 
                        if (fseg_get_nth_frag_page_no(seg_inode, i, mtr)
3286
 
                            == page) {
3287
 
 
3288
 
                                fseg_set_nth_frag_page_no(seg_inode, i,
3289
 
                                                          FIL_NULL, mtr);
3290
 
                                break;
3291
 
                        }
3292
 
                }
3293
 
 
3294
 
                fsp_free_page(space, zip_size, page, mtr);
3295
 
 
3296
 
                return;
3297
 
        }
3298
 
 
3299
 
        /* If we get here, the page is in some extent of the segment */
3300
 
 
3301
 
        descr_id = mach_read_from_8(descr + XDES_ID);
3302
 
        seg_id = mach_read_from_8(seg_inode + FSEG_ID);
3303
 
#if 0
3304
 
        fprintf(stderr,
3305
 
                "InnoDB: InnoDB is freeing space %lu page %lu,\n"
3306
 
                "InnoDB: which belongs to descr seg %llu\n"
3307
 
                "InnoDB: segment %llu.\n",
3308
 
                (ulong) space, (ulong) page,
3309
 
                (ullint) descr_id,
3310
 
                (ullint) seg_id);
3311
 
#endif /* 0 */
3312
 
        if (UNIV_UNLIKELY(descr_id != seg_id)) {
3313
 
                fputs("InnoDB: Dump of the tablespace extent descriptor: ",
3314
 
                      stderr);
3315
 
                ut_print_buf(stderr, descr, 40);
3316
 
                fputs("\nInnoDB: Dump of the segment inode: ", stderr);
3317
 
                ut_print_buf(stderr, seg_inode, 40);
3318
 
                putc('\n', stderr);
3319
 
 
3320
 
                fprintf(stderr,
3321
 
                        "InnoDB: Serious error: InnoDB is trying to"
3322
 
                        " free space %lu page %lu,\n"
3323
 
                        "InnoDB: which does not belong to"
3324
 
                        " segment %llu but belongs\n"
3325
 
                        "InnoDB: to segment %llu.\n",
3326
 
                        (ulong) space, (ulong) page,
3327
 
                        (ullint) descr_id,
3328
 
                        (ullint) seg_id);
3329
 
                goto crash;
3330
 
        }
3331
 
 
3332
 
        not_full_n_used = mtr_read_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3333
 
                                         MLOG_4BYTES, mtr);
3334
 
        if (xdes_is_full(descr, mtr)) {
3335
 
                /* The fragment is full: move it to another list */
3336
 
                flst_remove(seg_inode + FSEG_FULL,
3337
 
                            descr + XDES_FLST_NODE, mtr);
3338
 
                flst_add_last(seg_inode + FSEG_NOT_FULL,
3339
 
                              descr + XDES_FLST_NODE, mtr);
3340
 
                mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3341
 
                                 not_full_n_used + FSP_EXTENT_SIZE - 1,
3342
 
                                 MLOG_4BYTES, mtr);
3343
 
        } else {
3344
 
                ut_a(not_full_n_used > 0);
3345
 
                mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3346
 
                                 not_full_n_used - 1, MLOG_4BYTES, mtr);
3347
 
        }
3348
 
 
3349
 
        xdes_set_bit(descr, XDES_FREE_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3350
 
        xdes_set_bit(descr, XDES_CLEAN_BIT, page % FSP_EXTENT_SIZE, TRUE, mtr);
3351
 
 
3352
 
        if (xdes_is_free(descr, mtr)) {
3353
 
                /* The extent has become free: free it to space */
3354
 
                flst_remove(seg_inode + FSEG_NOT_FULL,
3355
 
                            descr + XDES_FLST_NODE, mtr);
3356
 
                fsp_free_extent(space, zip_size, page, mtr);
3357
 
        }
3358
 
}
3359
 
 
3360
 
/**********************************************************************//**
3361
 
Frees a single page of a segment. */
3362
 
UNIV_INTERN
3363
 
void
3364
 
fseg_free_page(
3365
 
/*===========*/
3366
 
        fseg_header_t*  seg_header, /*!< in: segment header */
3367
 
        ulint           space,  /*!< in: space id */
3368
 
        ulint           page,   /*!< in: page offset */
3369
 
        mtr_t*          mtr)    /*!< in: mtr handle */
3370
 
{
3371
 
        ulint           flags;
3372
 
        ulint           zip_size;
3373
 
        fseg_inode_t*   seg_inode;
3374
 
        rw_lock_t*      latch;
3375
 
 
3376
 
        latch = fil_space_get_latch(space, &flags);
3377
 
        zip_size = dict_table_flags_to_zip_size(flags);
3378
 
 
3379
 
        ut_ad(!mutex_own(&kernel_mutex)
3380
 
              || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3381
 
 
3382
 
        mtr_x_lock(latch, mtr);
3383
 
 
3384
 
        seg_inode = fseg_inode_get(seg_header, space, zip_size, mtr);
3385
 
 
3386
 
        fseg_free_page_low(seg_inode, space, zip_size, page, mtr);
3387
 
 
3388
 
#ifdef UNIV_DEBUG_FILE_ACCESSES
3389
 
        buf_page_set_file_page_was_freed(space, page);
3390
 
#endif
3391
 
}
3392
 
 
3393
 
/**********************************************************************//**
3394
 
Frees an extent of a segment to the space free list. */
3395
 
static
3396
 
void
3397
 
fseg_free_extent(
3398
 
/*=============*/
3399
 
        fseg_inode_t*   seg_inode, /*!< in: segment inode */
3400
 
        ulint           space,  /*!< in: space id */
3401
 
        ulint           zip_size,/*!< in: compressed page size in bytes
3402
 
                                or 0 for uncompressed pages */
3403
 
        ulint           page,   /*!< in: a page in the extent */
3404
 
        mtr_t*          mtr)    /*!< in: mtr handle */
3405
 
{
3406
 
        ulint   first_page_in_extent;
3407
 
        xdes_t* descr;
3408
 
        ulint   not_full_n_used;
3409
 
        ulint   descr_n_used;
3410
 
        ulint   i;
3411
 
 
3412
 
        ut_ad(seg_inode && mtr);
3413
 
 
3414
 
        descr = xdes_get_descriptor(space, zip_size, page, mtr);
3415
 
 
3416
 
        ut_a(xdes_get_state(descr, mtr) == XDES_FSEG);
3417
 
        ut_a(!memcmp(descr + XDES_ID, seg_inode + FSEG_ID, 8));
3418
 
        ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N)
3419
 
              == FSEG_MAGIC_N_VALUE);
3420
 
 
3421
 
        first_page_in_extent = page - (page % FSP_EXTENT_SIZE);
3422
 
 
3423
 
        for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3424
 
                if (FALSE == xdes_get_bit(descr, XDES_FREE_BIT, i, mtr)) {
3425
 
 
3426
 
                        /* Drop search system page hash index if the page is
3427
 
                        found in the pool and is hashed */
3428
 
 
3429
 
                        btr_search_drop_page_hash_when_freed(
3430
 
                                space, zip_size, first_page_in_extent + i);
3431
 
                }
3432
 
        }
3433
 
 
3434
 
        if (xdes_is_full(descr, mtr)) {
3435
 
                flst_remove(seg_inode + FSEG_FULL,
3436
 
                            descr + XDES_FLST_NODE, mtr);
3437
 
        } else if (xdes_is_free(descr, mtr)) {
3438
 
                flst_remove(seg_inode + FSEG_FREE,
3439
 
                            descr + XDES_FLST_NODE, mtr);
3440
 
        } else {
3441
 
                flst_remove(seg_inode + FSEG_NOT_FULL,
3442
 
                            descr + XDES_FLST_NODE, mtr);
3443
 
 
3444
 
                not_full_n_used = mtr_read_ulint(
3445
 
                        seg_inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr);
3446
 
 
3447
 
                descr_n_used = xdes_get_n_used(descr, mtr);
3448
 
                ut_a(not_full_n_used >= descr_n_used);
3449
 
                mlog_write_ulint(seg_inode + FSEG_NOT_FULL_N_USED,
3450
 
                                 not_full_n_used - descr_n_used,
3451
 
                                 MLOG_4BYTES, mtr);
3452
 
        }
3453
 
 
3454
 
        fsp_free_extent(space, zip_size, page, mtr);
3455
 
 
3456
 
#ifdef UNIV_DEBUG_FILE_ACCESSES
3457
 
        for (i = 0; i < FSP_EXTENT_SIZE; i++) {
3458
 
 
3459
 
                buf_page_set_file_page_was_freed(space,
3460
 
                                                 first_page_in_extent + i);
3461
 
        }
3462
 
#endif
3463
 
}
3464
 
 
3465
 
/**********************************************************************//**
3466
 
Frees part of a segment. This function can be used to free a segment by
3467
 
repeatedly calling this function in different mini-transactions. Doing
3468
 
the freeing in a single mini-transaction might result in too big a
3469
 
mini-transaction.
3470
 
@return TRUE if freeing completed */
3471
 
UNIV_INTERN
3472
 
ibool
3473
 
fseg_free_step(
3474
 
/*===========*/
3475
 
        fseg_header_t*  header, /*!< in, own: segment header; NOTE: if the header
3476
 
                                resides on the first page of the frag list
3477
 
                                of the segment, this pointer becomes obsolete
3478
 
                                after the last freeing step */
3479
 
        mtr_t*          mtr)    /*!< in: mtr */
3480
 
{
3481
 
        ulint           n;
3482
 
        ulint           page;
3483
 
        xdes_t*         descr;
3484
 
        fseg_inode_t*   inode;
3485
 
        ulint           space;
3486
 
        ulint           flags;
3487
 
        ulint           zip_size;
3488
 
        ulint           header_page;
3489
 
        rw_lock_t*      latch;
3490
 
 
3491
 
        space = page_get_space_id(page_align(header));
3492
 
        header_page = page_get_page_no(page_align(header));
3493
 
 
3494
 
        latch = fil_space_get_latch(space, &flags);
3495
 
        zip_size = dict_table_flags_to_zip_size(flags);
3496
 
 
3497
 
        ut_ad(!mutex_own(&kernel_mutex)
3498
 
              || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3499
 
 
3500
 
        mtr_x_lock(latch, mtr);
3501
 
 
3502
 
        descr = xdes_get_descriptor(space, zip_size, header_page, mtr);
3503
 
 
3504
 
        /* Check that the header resides on a page which has not been
3505
 
        freed yet */
3506
 
 
3507
 
        ut_a(descr);
3508
 
        ut_a(xdes_get_bit(descr, XDES_FREE_BIT,
3509
 
                          header_page % FSP_EXTENT_SIZE, mtr) == FALSE);
3510
 
        inode = fseg_inode_try_get(header, space, zip_size, mtr);
3511
 
 
3512
 
        if (UNIV_UNLIKELY(inode == NULL)) {
3513
 
                fprintf(stderr, "double free of inode from %u:%u\n",
3514
 
                        (unsigned) space, (unsigned) header_page);
3515
 
                return(TRUE);
3516
 
        }
3517
 
 
3518
 
        descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3519
 
 
3520
 
        if (descr != NULL) {
3521
 
                /* Free the extent held by the segment */
3522
 
                page = xdes_get_offset(descr);
3523
 
 
3524
 
                fseg_free_extent(inode, space, zip_size, page, mtr);
3525
 
 
3526
 
                return(FALSE);
3527
 
        }
3528
 
 
3529
 
        /* Free a frag page */
3530
 
        n = fseg_find_last_used_frag_page_slot(inode, mtr);
3531
 
 
3532
 
        if (n == ULINT_UNDEFINED) {
3533
 
                /* Freeing completed: free the segment inode */
3534
 
                fsp_free_seg_inode(space, zip_size, inode, mtr);
3535
 
 
3536
 
                return(TRUE);
3537
 
        }
3538
 
 
3539
 
        fseg_free_page_low(inode, space, zip_size,
3540
 
                           fseg_get_nth_frag_page_no(inode, n, mtr), mtr);
3541
 
 
3542
 
        n = fseg_find_last_used_frag_page_slot(inode, mtr);
3543
 
 
3544
 
        if (n == ULINT_UNDEFINED) {
3545
 
                /* Freeing completed: free the segment inode */
3546
 
                fsp_free_seg_inode(space, zip_size, inode, mtr);
3547
 
 
3548
 
                return(TRUE);
3549
 
        }
3550
 
 
3551
 
        return(FALSE);
3552
 
}
3553
 
 
3554
 
/**********************************************************************//**
3555
 
Frees part of a segment. Differs from fseg_free_step because this function
3556
 
leaves the header page unfreed.
3557
 
@return TRUE if freeing completed, except the header page */
3558
 
UNIV_INTERN
3559
 
ibool
3560
 
fseg_free_step_not_header(
3561
 
/*======================*/
3562
 
        fseg_header_t*  header, /*!< in: segment header which must reside on
3563
 
                                the first fragment page of the segment */
3564
 
        mtr_t*          mtr)    /*!< in: mtr */
3565
 
{
3566
 
        ulint           n;
3567
 
        ulint           page;
3568
 
        xdes_t*         descr;
3569
 
        fseg_inode_t*   inode;
3570
 
        ulint           space;
3571
 
        ulint           flags;
3572
 
        ulint           zip_size;
3573
 
        ulint           page_no;
3574
 
        rw_lock_t*      latch;
3575
 
 
3576
 
        space = page_get_space_id(page_align(header));
3577
 
 
3578
 
        latch = fil_space_get_latch(space, &flags);
3579
 
        zip_size = dict_table_flags_to_zip_size(flags);
3580
 
 
3581
 
        ut_ad(!mutex_own(&kernel_mutex)
3582
 
              || mtr_memo_contains(mtr, latch, MTR_MEMO_X_LOCK));
3583
 
 
3584
 
        mtr_x_lock(latch, mtr);
3585
 
 
3586
 
        inode = fseg_inode_get(header, space, zip_size, mtr);
3587
 
 
3588
 
        descr = fseg_get_first_extent(inode, space, zip_size, mtr);
3589
 
 
3590
 
        if (descr != NULL) {
3591
 
                /* Free the extent held by the segment */
3592
 
                page = xdes_get_offset(descr);
3593
 
 
3594
 
                fseg_free_extent(inode, space, zip_size, page, mtr);
3595
 
 
3596
 
                return(FALSE);
3597
 
        }
3598
 
 
3599
 
        /* Free a frag page */
3600
 
 
3601
 
        n = fseg_find_last_used_frag_page_slot(inode, mtr);
3602
 
 
3603
 
        if (n == ULINT_UNDEFINED) {
3604
 
                ut_error;
3605
 
        }
3606
 
 
3607
 
        page_no = fseg_get_nth_frag_page_no(inode, n, mtr);
3608
 
 
3609
 
        if (page_no == page_get_page_no(page_align(header))) {
3610
 
 
3611
 
                return(TRUE);
3612
 
        }
3613
 
 
3614
 
        fseg_free_page_low(inode, space, zip_size, page_no, mtr);
3615
 
 
3616
 
        return(FALSE);
3617
 
}
3618
 
 
3619
 
/**********************************************************************//**
3620
 
Returns the first extent descriptor for a segment. We think of the extent
3621
 
lists of the segment catenated in the order FSEG_FULL -> FSEG_NOT_FULL
3622
 
-> FSEG_FREE.
3623
 
@return the first extent descriptor, or NULL if none */
3624
 
static
3625
 
xdes_t*
3626
 
fseg_get_first_extent(
3627
 
/*==================*/
3628
 
        fseg_inode_t*   inode,  /*!< in: segment inode */
3629
 
        ulint           space,  /*!< in: space id */
3630
 
        ulint           zip_size,/*!< in: compressed page size in bytes
3631
 
                                or 0 for uncompressed pages */
3632
 
        mtr_t*          mtr)    /*!< in: mtr */
3633
 
{
3634
 
        fil_addr_t      first;
3635
 
        xdes_t*         descr;
3636
 
 
3637
 
        ut_ad(inode && mtr);
3638
 
 
3639
 
        ut_ad(space == page_get_space_id(page_align(inode)));
3640
 
        ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3641
 
 
3642
 
        first = fil_addr_null;
3643
 
 
3644
 
        if (flst_get_len(inode + FSEG_FULL, mtr) > 0) {
3645
 
 
3646
 
                first = flst_get_first(inode + FSEG_FULL, mtr);
3647
 
 
3648
 
        } else if (flst_get_len(inode + FSEG_NOT_FULL, mtr) > 0) {
3649
 
 
3650
 
                first = flst_get_first(inode + FSEG_NOT_FULL, mtr);
3651
 
 
3652
 
        } else if (flst_get_len(inode + FSEG_FREE, mtr) > 0) {
3653
 
 
3654
 
                first = flst_get_first(inode + FSEG_FREE, mtr);
3655
 
        }
3656
 
 
3657
 
        if (first.page == FIL_NULL) {
3658
 
 
3659
 
                return(NULL);
3660
 
        }
3661
 
        descr = xdes_lst_get_descriptor(space, zip_size, first, mtr);
3662
 
 
3663
 
        return(descr);
3664
 
}
3665
 
 
3666
 
/*******************************************************************//**
3667
 
Validates a segment.
3668
 
@return TRUE if ok */
3669
 
static
3670
 
ibool
3671
 
fseg_validate_low(
3672
 
/*==============*/
3673
 
        fseg_inode_t*   inode, /*!< in: segment inode */
3674
 
        mtr_t*          mtr2)   /*!< in: mtr */
3675
 
{
3676
 
        ulint           space;
3677
 
        ib_id_t         seg_id;
3678
 
        mtr_t           mtr;
3679
 
        xdes_t*         descr;
3680
 
        fil_addr_t      node_addr;
3681
 
        ulint           n_used          = 0;
3682
 
        ulint           n_used2         = 0;
3683
 
 
3684
 
        ut_ad(mtr_memo_contains_page(mtr2, inode, MTR_MEMO_PAGE_X_FIX));
3685
 
        ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3686
 
 
3687
 
        space = page_get_space_id(page_align(inode));
3688
 
 
3689
 
        seg_id = mach_read_from_8(inode + FSEG_ID);
3690
 
        n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3691
 
                                MLOG_4BYTES, mtr2);
3692
 
        flst_validate(inode + FSEG_FREE, mtr2);
3693
 
        flst_validate(inode + FSEG_NOT_FULL, mtr2);
3694
 
        flst_validate(inode + FSEG_FULL, mtr2);
3695
 
 
3696
 
        /* Validate FSEG_FREE list */
3697
 
        node_addr = flst_get_first(inode + FSEG_FREE, mtr2);
3698
 
 
3699
 
        while (!fil_addr_is_null(node_addr)) {
3700
 
                ulint   flags;
3701
 
                ulint   zip_size;
3702
 
 
3703
 
                mtr_start(&mtr);
3704
 
                mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3705
 
                zip_size = dict_table_flags_to_zip_size(flags);
3706
 
 
3707
 
                descr = xdes_lst_get_descriptor(space, zip_size,
3708
 
                                                node_addr, &mtr);
3709
 
 
3710
 
                ut_a(xdes_get_n_used(descr, &mtr) == 0);
3711
 
                ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3712
 
                ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
3713
 
 
3714
 
                node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3715
 
                mtr_commit(&mtr);
3716
 
        }
3717
 
 
3718
 
        /* Validate FSEG_NOT_FULL list */
3719
 
 
3720
 
        node_addr = flst_get_first(inode + FSEG_NOT_FULL, mtr2);
3721
 
 
3722
 
        while (!fil_addr_is_null(node_addr)) {
3723
 
                ulint   flags;
3724
 
                ulint   zip_size;
3725
 
 
3726
 
                mtr_start(&mtr);
3727
 
                mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3728
 
                zip_size = dict_table_flags_to_zip_size(flags);
3729
 
 
3730
 
                descr = xdes_lst_get_descriptor(space, zip_size,
3731
 
                                                node_addr, &mtr);
3732
 
 
3733
 
                ut_a(xdes_get_n_used(descr, &mtr) > 0);
3734
 
                ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3735
 
                ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3736
 
                ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
3737
 
 
3738
 
                n_used2 += xdes_get_n_used(descr, &mtr);
3739
 
 
3740
 
                node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3741
 
                mtr_commit(&mtr);
3742
 
        }
3743
 
 
3744
 
        /* Validate FSEG_FULL list */
3745
 
 
3746
 
        node_addr = flst_get_first(inode + FSEG_FULL, mtr2);
3747
 
 
3748
 
        while (!fil_addr_is_null(node_addr)) {
3749
 
                ulint   flags;
3750
 
                ulint   zip_size;
3751
 
 
3752
 
                mtr_start(&mtr);
3753
 
                mtr_x_lock(fil_space_get_latch(space, &flags), &mtr);
3754
 
                zip_size = dict_table_flags_to_zip_size(flags);
3755
 
 
3756
 
                descr = xdes_lst_get_descriptor(space, zip_size,
3757
 
                                                node_addr, &mtr);
3758
 
 
3759
 
                ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
3760
 
                ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG);
3761
 
                ut_a(mach_read_from_8(descr + XDES_ID) == seg_id);
3762
 
 
3763
 
                node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3764
 
                mtr_commit(&mtr);
3765
 
        }
3766
 
 
3767
 
        ut_a(n_used == n_used2);
3768
 
 
3769
 
        return(TRUE);
3770
 
}
3771
 
 
3772
 
#ifdef UNIV_DEBUG
3773
 
/*******************************************************************//**
3774
 
Validates a segment.
3775
 
@return TRUE if ok */
3776
 
UNIV_INTERN
3777
 
ibool
3778
 
fseg_validate(
3779
 
/*==========*/
3780
 
        fseg_header_t*  header, /*!< in: segment header */
3781
 
        mtr_t*          mtr)    /*!< in: mtr */
3782
 
{
3783
 
        fseg_inode_t*   inode;
3784
 
        ibool           ret;
3785
 
        ulint           space;
3786
 
        ulint           flags;
3787
 
        ulint           zip_size;
3788
 
 
3789
 
        space = page_get_space_id(page_align(header));
3790
 
 
3791
 
        mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3792
 
        zip_size = dict_table_flags_to_zip_size(flags);
3793
 
 
3794
 
        inode = fseg_inode_get(header, space, zip_size, mtr);
3795
 
 
3796
 
        ret = fseg_validate_low(inode, mtr);
3797
 
 
3798
 
        return(ret);
3799
 
}
3800
 
#endif /* UNIV_DEBUG */
3801
 
 
3802
 
/*******************************************************************//**
3803
 
Writes info of a segment. */
3804
 
static
3805
 
void
3806
 
fseg_print_low(
3807
 
/*===========*/
3808
 
        fseg_inode_t*   inode, /*!< in: segment inode */
3809
 
        mtr_t*          mtr)    /*!< in: mtr */
3810
 
{
3811
 
        ulint   space;
3812
 
        ulint   n_used;
3813
 
        ulint   n_frag;
3814
 
        ulint   n_free;
3815
 
        ulint   n_not_full;
3816
 
        ulint   n_full;
3817
 
        ulint   reserved;
3818
 
        ulint   used;
3819
 
        ulint   page_no;
3820
 
        ib_id_t seg_id;
3821
 
 
3822
 
        ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX));
3823
 
        space = page_get_space_id(page_align(inode));
3824
 
        page_no = page_get_page_no(page_align(inode));
3825
 
 
3826
 
        reserved = fseg_n_reserved_pages_low(inode, &used, mtr);
3827
 
 
3828
 
        seg_id = mach_read_from_8(inode + FSEG_ID);
3829
 
 
3830
 
        n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED,
3831
 
                                MLOG_4BYTES, mtr);
3832
 
        n_frag = fseg_get_n_frag_pages(inode, mtr);
3833
 
        n_free = flst_get_len(inode + FSEG_FREE, mtr);
3834
 
        n_not_full = flst_get_len(inode + FSEG_NOT_FULL, mtr);
3835
 
        n_full = flst_get_len(inode + FSEG_FULL, mtr);
3836
 
 
3837
 
        fprintf(stderr,
3838
 
                "SEGMENT id %llu space %lu; page %lu;"
3839
 
                " res %lu used %lu; full ext %lu\n"
3840
 
                "fragm pages %lu; free extents %lu;"
3841
 
                " not full extents %lu: pages %lu\n",
3842
 
                (ullint) seg_id,
3843
 
                (ulong) space, (ulong) page_no,
3844
 
                (ulong) reserved, (ulong) used, (ulong) n_full,
3845
 
                (ulong) n_frag, (ulong) n_free, (ulong) n_not_full,
3846
 
                (ulong) n_used);
3847
 
        ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE);
3848
 
}
3849
 
 
3850
 
#ifdef UNIV_BTR_PRINT
3851
 
/*******************************************************************//**
3852
 
Writes info of a segment. */
3853
 
UNIV_INTERN
3854
 
void
3855
 
fseg_print(
3856
 
/*=======*/
3857
 
        fseg_header_t*  header, /*!< in: segment header */
3858
 
        mtr_t*          mtr)    /*!< in: mtr */
3859
 
{
3860
 
        fseg_inode_t*   inode;
3861
 
        ulint           space;
3862
 
        ulint           flags;
3863
 
        ulint           zip_size;
3864
 
 
3865
 
        space = page_get_space_id(page_align(header));
3866
 
 
3867
 
        mtr_x_lock(fil_space_get_latch(space, &flags), mtr);
3868
 
        zip_size = dict_table_flags_to_zip_size(flags);
3869
 
 
3870
 
        inode = fseg_inode_get(header, space, zip_size, mtr);
3871
 
 
3872
 
        fseg_print_low(inode, mtr);
3873
 
}
3874
 
#endif /* UNIV_BTR_PRINT */
3875
 
 
3876
 
/*******************************************************************//**
3877
 
Validates the file space system and its segments.
3878
 
@return TRUE if ok */
3879
 
UNIV_INTERN
3880
 
ibool
3881
 
fsp_validate(
3882
 
/*=========*/
3883
 
        ulint   space)  /*!< in: space id */
3884
 
{
3885
 
        fsp_header_t*   header;
3886
 
        fseg_inode_t*   seg_inode;
3887
 
        page_t*         seg_inode_page;
3888
 
        rw_lock_t*      latch;
3889
 
        ulint           size;
3890
 
        ulint           flags;
3891
 
        ulint           zip_size;
3892
 
        ulint           free_limit;
3893
 
        ulint           frag_n_used;
3894
 
        mtr_t           mtr;
3895
 
        mtr_t           mtr2;
3896
 
        xdes_t*         descr;
3897
 
        fil_addr_t      node_addr;
3898
 
        fil_addr_t      next_node_addr;
3899
 
        ulint           descr_count     = 0;
3900
 
        ulint           n_used          = 0;
3901
 
        ulint           n_used2         = 0;
3902
 
        ulint           n_full_frag_pages;
3903
 
        ulint           n;
3904
 
        ulint           seg_inode_len_free;
3905
 
        ulint           seg_inode_len_full;
3906
 
 
3907
 
        latch = fil_space_get_latch(space, &flags);
3908
 
        zip_size = dict_table_flags_to_zip_size(flags);
3909
 
        ut_a(ut_is_2pow(zip_size));
3910
 
        ut_a(zip_size <= UNIV_PAGE_SIZE);
3911
 
        ut_a(!zip_size || zip_size >= PAGE_ZIP_MIN_SIZE);
3912
 
 
3913
 
        /* Start first a mini-transaction mtr2 to lock out all other threads
3914
 
        from the fsp system */
3915
 
        mtr_start(&mtr2);
3916
 
        mtr_x_lock(latch, &mtr2);
3917
 
 
3918
 
        mtr_start(&mtr);
3919
 
        mtr_x_lock(latch, &mtr);
3920
 
 
3921
 
        header = fsp_get_space_header(space, zip_size, &mtr);
3922
 
 
3923
 
        size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
3924
 
        free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT,
3925
 
                                    MLOG_4BYTES, &mtr);
3926
 
        frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED,
3927
 
                                     MLOG_4BYTES, &mtr);
3928
 
 
3929
 
        n_full_frag_pages = FSP_EXTENT_SIZE
3930
 
                * flst_get_len(header + FSP_FULL_FRAG, &mtr);
3931
 
 
3932
 
        if (UNIV_UNLIKELY(free_limit > size)) {
3933
 
 
3934
 
                ut_a(space != 0);
3935
 
                ut_a(size < FSP_EXTENT_SIZE);
3936
 
        }
3937
 
 
3938
 
        flst_validate(header + FSP_FREE, &mtr);
3939
 
        flst_validate(header + FSP_FREE_FRAG, &mtr);
3940
 
        flst_validate(header + FSP_FULL_FRAG, &mtr);
3941
 
 
3942
 
        mtr_commit(&mtr);
3943
 
 
3944
 
        /* Validate FSP_FREE list */
3945
 
        mtr_start(&mtr);
3946
 
        mtr_x_lock(latch, &mtr);
3947
 
 
3948
 
        header = fsp_get_space_header(space, zip_size, &mtr);
3949
 
        node_addr = flst_get_first(header + FSP_FREE, &mtr);
3950
 
 
3951
 
        mtr_commit(&mtr);
3952
 
 
3953
 
        while (!fil_addr_is_null(node_addr)) {
3954
 
                mtr_start(&mtr);
3955
 
                mtr_x_lock(latch, &mtr);
3956
 
 
3957
 
                descr_count++;
3958
 
                descr = xdes_lst_get_descriptor(space, zip_size,
3959
 
                                                node_addr, &mtr);
3960
 
 
3961
 
                ut_a(xdes_get_n_used(descr, &mtr) == 0);
3962
 
                ut_a(xdes_get_state(descr, &mtr) == XDES_FREE);
3963
 
 
3964
 
                node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3965
 
                mtr_commit(&mtr);
3966
 
        }
3967
 
 
3968
 
        /* Validate FSP_FREE_FRAG list */
3969
 
        mtr_start(&mtr);
3970
 
        mtr_x_lock(latch, &mtr);
3971
 
 
3972
 
        header = fsp_get_space_header(space, zip_size, &mtr);
3973
 
        node_addr = flst_get_first(header + FSP_FREE_FRAG, &mtr);
3974
 
 
3975
 
        mtr_commit(&mtr);
3976
 
 
3977
 
        while (!fil_addr_is_null(node_addr)) {
3978
 
                mtr_start(&mtr);
3979
 
                mtr_x_lock(latch, &mtr);
3980
 
 
3981
 
                descr_count++;
3982
 
                descr = xdes_lst_get_descriptor(space, zip_size,
3983
 
                                                node_addr, &mtr);
3984
 
 
3985
 
                ut_a(xdes_get_n_used(descr, &mtr) > 0);
3986
 
                ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE);
3987
 
                ut_a(xdes_get_state(descr, &mtr) == XDES_FREE_FRAG);
3988
 
 
3989
 
                n_used += xdes_get_n_used(descr, &mtr);
3990
 
                node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
3991
 
 
3992
 
                mtr_commit(&mtr);
3993
 
        }
3994
 
 
3995
 
        /* Validate FSP_FULL_FRAG list */
3996
 
        mtr_start(&mtr);
3997
 
        mtr_x_lock(latch, &mtr);
3998
 
 
3999
 
        header = fsp_get_space_header(space, zip_size, &mtr);
4000
 
        node_addr = flst_get_first(header + FSP_FULL_FRAG, &mtr);
4001
 
 
4002
 
        mtr_commit(&mtr);
4003
 
 
4004
 
        while (!fil_addr_is_null(node_addr)) {
4005
 
                mtr_start(&mtr);
4006
 
                mtr_x_lock(latch, &mtr);
4007
 
 
4008
 
                descr_count++;
4009
 
                descr = xdes_lst_get_descriptor(space, zip_size,
4010
 
                                                node_addr, &mtr);
4011
 
 
4012
 
                ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE);
4013
 
                ut_a(xdes_get_state(descr, &mtr) == XDES_FULL_FRAG);
4014
 
 
4015
 
                node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr);
4016
 
                mtr_commit(&mtr);
4017
 
        }
4018
 
 
4019
 
        /* Validate segments */
4020
 
        mtr_start(&mtr);
4021
 
        mtr_x_lock(latch, &mtr);
4022
 
 
4023
 
        header = fsp_get_space_header(space, zip_size, &mtr);
4024
 
 
4025
 
        node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
4026
 
 
4027
 
        seg_inode_len_full = flst_get_len(header + FSP_SEG_INODES_FULL, &mtr);
4028
 
 
4029
 
        mtr_commit(&mtr);
4030
 
 
4031
 
        while (!fil_addr_is_null(node_addr)) {
4032
 
 
4033
 
                n = 0;
4034
 
                do {
4035
 
                        mtr_start(&mtr);
4036
 
                        mtr_x_lock(latch, &mtr);
4037
 
 
4038
 
                        seg_inode_page = fut_get_ptr(
4039
 
                                space, zip_size, node_addr, RW_X_LATCH, &mtr)
4040
 
                                - FSEG_INODE_PAGE_NODE;
4041
 
 
4042
 
                        seg_inode = fsp_seg_inode_page_get_nth_inode(
4043
 
                                seg_inode_page, n, zip_size, &mtr);
4044
 
                        ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0);
4045
 
                        fseg_validate_low(seg_inode, &mtr);
4046
 
 
4047
 
                        descr_count += flst_get_len(seg_inode + FSEG_FREE,
4048
 
                                                    &mtr);
4049
 
                        descr_count += flst_get_len(seg_inode + FSEG_FULL,
4050
 
                                                    &mtr);
4051
 
                        descr_count += flst_get_len(seg_inode + FSEG_NOT_FULL,
4052
 
                                                    &mtr);
4053
 
 
4054
 
                        n_used2 += fseg_get_n_frag_pages(seg_inode, &mtr);
4055
 
 
4056
 
                        next_node_addr = flst_get_next_addr(
4057
 
                                seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4058
 
                        mtr_commit(&mtr);
4059
 
                } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4060
 
 
4061
 
                node_addr = next_node_addr;
4062
 
        }
4063
 
 
4064
 
        mtr_start(&mtr);
4065
 
        mtr_x_lock(latch, &mtr);
4066
 
 
4067
 
        header = fsp_get_space_header(space, zip_size, &mtr);
4068
 
 
4069
 
        node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
4070
 
 
4071
 
        seg_inode_len_free = flst_get_len(header + FSP_SEG_INODES_FREE, &mtr);
4072
 
 
4073
 
        mtr_commit(&mtr);
4074
 
 
4075
 
        while (!fil_addr_is_null(node_addr)) {
4076
 
 
4077
 
                n = 0;
4078
 
 
4079
 
                do {
4080
 
                        mtr_start(&mtr);
4081
 
                        mtr_x_lock(latch, &mtr);
4082
 
 
4083
 
                        seg_inode_page = fut_get_ptr(
4084
 
                                space, zip_size, node_addr, RW_X_LATCH, &mtr)
4085
 
                                - FSEG_INODE_PAGE_NODE;
4086
 
 
4087
 
                        seg_inode = fsp_seg_inode_page_get_nth_inode(
4088
 
                                seg_inode_page, n, zip_size, &mtr);
4089
 
                        if (mach_read_from_8(seg_inode + FSEG_ID)) {
4090
 
                                fseg_validate_low(seg_inode, &mtr);
4091
 
 
4092
 
                                descr_count += flst_get_len(
4093
 
                                        seg_inode + FSEG_FREE, &mtr);
4094
 
                                descr_count += flst_get_len(
4095
 
                                        seg_inode + FSEG_FULL, &mtr);
4096
 
                                descr_count += flst_get_len(
4097
 
                                        seg_inode + FSEG_NOT_FULL, &mtr);
4098
 
                                n_used2 += fseg_get_n_frag_pages(
4099
 
                                        seg_inode, &mtr);
4100
 
                        }
4101
 
 
4102
 
                        next_node_addr = flst_get_next_addr(
4103
 
                                seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4104
 
                        mtr_commit(&mtr);
4105
 
                } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4106
 
 
4107
 
                node_addr = next_node_addr;
4108
 
        }
4109
 
 
4110
 
        ut_a(descr_count * FSP_EXTENT_SIZE == free_limit);
4111
 
        if (!zip_size) {
4112
 
                ut_a(n_used + n_full_frag_pages
4113
 
                     == n_used2 + 2 * ((free_limit + (UNIV_PAGE_SIZE - 1))
4114
 
                                       / UNIV_PAGE_SIZE)
4115
 
                     + seg_inode_len_full + seg_inode_len_free);
4116
 
        } else {
4117
 
                ut_a(n_used + n_full_frag_pages
4118
 
                     == n_used2 + 2 * ((free_limit + (zip_size - 1))
4119
 
                                       / zip_size)
4120
 
                     + seg_inode_len_full + seg_inode_len_free);
4121
 
        }
4122
 
        ut_a(frag_n_used == n_used);
4123
 
 
4124
 
        mtr_commit(&mtr2);
4125
 
 
4126
 
        return(TRUE);
4127
 
}
4128
 
 
4129
 
/*******************************************************************//**
4130
 
Prints info of a file space. */
4131
 
UNIV_INTERN
4132
 
void
4133
 
fsp_print(
4134
 
/*======*/
4135
 
        ulint   space)  /*!< in: space id */
4136
 
{
4137
 
        fsp_header_t*   header;
4138
 
        fseg_inode_t*   seg_inode;
4139
 
        page_t*         seg_inode_page;
4140
 
        rw_lock_t*      latch;
4141
 
        ulint           flags;
4142
 
        ulint           zip_size;
4143
 
        ulint           size;
4144
 
        ulint           free_limit;
4145
 
        ulint           frag_n_used;
4146
 
        fil_addr_t      node_addr;
4147
 
        fil_addr_t      next_node_addr;
4148
 
        ulint           n_free;
4149
 
        ulint           n_free_frag;
4150
 
        ulint           n_full_frag;
4151
 
        ib_id_t         seg_id;
4152
 
        ulint           n;
4153
 
        ulint           n_segs          = 0;
4154
 
        mtr_t           mtr;
4155
 
        mtr_t           mtr2;
4156
 
 
4157
 
        latch = fil_space_get_latch(space, &flags);
4158
 
        zip_size = dict_table_flags_to_zip_size(flags);
4159
 
 
4160
 
        /* Start first a mini-transaction mtr2 to lock out all other threads
4161
 
        from the fsp system */
4162
 
 
4163
 
        mtr_start(&mtr2);
4164
 
 
4165
 
        mtr_x_lock(latch, &mtr2);
4166
 
 
4167
 
        mtr_start(&mtr);
4168
 
 
4169
 
        mtr_x_lock(latch, &mtr);
4170
 
 
4171
 
        header = fsp_get_space_header(space, zip_size, &mtr);
4172
 
 
4173
 
        size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, &mtr);
4174
 
 
4175
 
        free_limit = mtr_read_ulint(header + FSP_FREE_LIMIT, MLOG_4BYTES,
4176
 
                                    &mtr);
4177
 
        frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
4178
 
                                     &mtr);
4179
 
        n_free = flst_get_len(header + FSP_FREE, &mtr);
4180
 
        n_free_frag = flst_get_len(header + FSP_FREE_FRAG, &mtr);
4181
 
        n_full_frag = flst_get_len(header + FSP_FULL_FRAG, &mtr);
4182
 
 
4183
 
        seg_id = mach_read_from_8(header + FSP_SEG_ID);
4184
 
 
4185
 
        fprintf(stderr,
4186
 
                "FILE SPACE INFO: id %lu\n"
4187
 
                "size %lu, free limit %lu, free extents %lu\n"
4188
 
                "not full frag extents %lu: used pages %lu,"
4189
 
                " full frag extents %lu\n"
4190
 
                "first seg id not used %llu\n",
4191
 
                (ulong) space,
4192
 
                (ulong) size, (ulong) free_limit, (ulong) n_free,
4193
 
                (ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag,
4194
 
                (ullint) seg_id);
4195
 
 
4196
 
        mtr_commit(&mtr);
4197
 
 
4198
 
        /* Print segments */
4199
 
 
4200
 
        mtr_start(&mtr);
4201
 
        mtr_x_lock(latch, &mtr);
4202
 
 
4203
 
        header = fsp_get_space_header(space, zip_size, &mtr);
4204
 
 
4205
 
        node_addr = flst_get_first(header + FSP_SEG_INODES_FULL, &mtr);
4206
 
 
4207
 
        mtr_commit(&mtr);
4208
 
 
4209
 
        while (!fil_addr_is_null(node_addr)) {
4210
 
 
4211
 
                n = 0;
4212
 
 
4213
 
                do {
4214
 
 
4215
 
                        mtr_start(&mtr);
4216
 
                        mtr_x_lock(latch, &mtr);
4217
 
 
4218
 
                        seg_inode_page = fut_get_ptr(
4219
 
                                space, zip_size, node_addr, RW_X_LATCH, &mtr)
4220
 
                                - FSEG_INODE_PAGE_NODE;
4221
 
 
4222
 
                        seg_inode = fsp_seg_inode_page_get_nth_inode(
4223
 
                                seg_inode_page, n, zip_size, &mtr);
4224
 
                        ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0);
4225
 
                        fseg_print_low(seg_inode, &mtr);
4226
 
 
4227
 
                        n_segs++;
4228
 
 
4229
 
                        next_node_addr = flst_get_next_addr(
4230
 
                                seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4231
 
                        mtr_commit(&mtr);
4232
 
                } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4233
 
 
4234
 
                node_addr = next_node_addr;
4235
 
        }
4236
 
 
4237
 
        mtr_start(&mtr);
4238
 
        mtr_x_lock(latch, &mtr);
4239
 
 
4240
 
        header = fsp_get_space_header(space, zip_size, &mtr);
4241
 
 
4242
 
        node_addr = flst_get_first(header + FSP_SEG_INODES_FREE, &mtr);
4243
 
 
4244
 
        mtr_commit(&mtr);
4245
 
 
4246
 
        while (!fil_addr_is_null(node_addr)) {
4247
 
 
4248
 
                n = 0;
4249
 
 
4250
 
                do {
4251
 
 
4252
 
                        mtr_start(&mtr);
4253
 
                        mtr_x_lock(latch, &mtr);
4254
 
 
4255
 
                        seg_inode_page = fut_get_ptr(
4256
 
                                space, zip_size, node_addr, RW_X_LATCH, &mtr)
4257
 
                                - FSEG_INODE_PAGE_NODE;
4258
 
 
4259
 
                        seg_inode = fsp_seg_inode_page_get_nth_inode(
4260
 
                                seg_inode_page, n, zip_size, &mtr);
4261
 
                        if (mach_read_from_8(seg_inode + FSEG_ID)) {
4262
 
 
4263
 
                                fseg_print_low(seg_inode, &mtr);
4264
 
                                n_segs++;
4265
 
                        }
4266
 
 
4267
 
                        next_node_addr = flst_get_next_addr(
4268
 
                                seg_inode_page + FSEG_INODE_PAGE_NODE, &mtr);
4269
 
                        mtr_commit(&mtr);
4270
 
                } while (++n < FSP_SEG_INODES_PER_PAGE(zip_size));
4271
 
 
4272
 
                node_addr = next_node_addr;
4273
 
        }
4274
 
 
4275
 
        mtr_commit(&mtr2);
4276
 
 
4277
 
        fprintf(stderr, "NUMBER of file segments: %lu\n", (ulong) n_segs);
4278
 
}
4279
 
#endif /* !UNIV_HOTBACKUP */