~drizzle-trunk/drizzle/development

« back to all changes in this revision

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

  • Committer: Brian Aker
  • Date: 2010-02-10 18:04:24 UTC
  • mfrom: (1286.1.5 build)
  • Revision ID: brian@gaz-20100210180424-03ypoyifmlc2lgcp
Merge of Brian/Padraig

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