~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

Show diffs side-by-side

added added

removed removed

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