~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

Tags: innodb-plugin-1.0.1
Imported 1.0.1 with clean - with no changes.

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
}