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

« back to all changes in this revision

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

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

Show diffs side-by-side

added added

removed removed

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