~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Monty Taylor
  • Date: 2009-04-26 19:40:09 UTC
  • mto: (997.2.25 mordred)
  • mto: This revision was merged to the branch mainline in revision 1003.
  • Revision ID: mordred@inaugust.com-20090426194009-dhnrewc3dyc2zv5a
Fixed an or tatement.

Show diffs side-by-side

added added

removed removed

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