~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

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
}