1/*****************************************************************************
2
3Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2013, 2018, MariaDB Corporation.
5
6This program is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free Software
8Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program; if not, write to the Free Software Foundation, Inc.,
1651 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17
18*****************************************************************************/
19
20/**************************************************//**
21@file include/fsp0fsp.h
22File space management
23
24Created 12/18/1995 Heikki Tuuri
25*******************************************************/
26
27#ifndef fsp0fsp_h
28#define fsp0fsp_h
29
30#include "univ.i"
31
32#include "fsp0types.h"
33
34#ifndef UNIV_INNOCHECKSUM
35
36#include "fsp0space.h"
37#include "fut0lst.h"
38#include "mtr0mtr.h"
39#include "page0types.h"
40#include "rem0types.h"
41#include "ut0byte.h"
42
43#endif /* !UNIV_INNOCHECKSUM */
44#include "fsp0types.h"
45
46/** @return the PAGE_SSIZE flags for the current innodb_page_size */
47#define FSP_FLAGS_PAGE_SSIZE() \
48 ((srv_page_size == UNIV_PAGE_SIZE_ORIG) ? \
49 0U : (srv_page_size_shift - UNIV_ZIP_SIZE_SHIFT_MIN + 1) \
50 << FSP_FLAGS_POS_PAGE_SSIZE)
51
52/* @defgroup Compatibility macros for MariaDB 10.1.0 through 10.1.20;
53see the table in fsp0types.h @{ */
54/** Zero relative shift position of the PAGE_COMPRESSION field */
55#define FSP_FLAGS_POS_PAGE_COMPRESSION_MARIADB101 \
56 (FSP_FLAGS_POS_ATOMIC_BLOBS \
57 + FSP_FLAGS_WIDTH_ATOMIC_BLOBS)
58/** Zero relative shift position of the PAGE_COMPRESSION_LEVEL field */
59#define FSP_FLAGS_POS_PAGE_COMPRESSION_LEVEL_MARIADB101 \
60 (FSP_FLAGS_POS_PAGE_COMPRESSION_MARIADB101 + 1)
61/** Zero relative shift position of the ATOMIC_WRITES field */
62#define FSP_FLAGS_POS_ATOMIC_WRITES_MARIADB101 \
63 (FSP_FLAGS_POS_PAGE_COMPRESSION_LEVEL_MARIADB101 + 4)
64/** Zero relative shift position of the PAGE_SSIZE field */
65#define FSP_FLAGS_POS_PAGE_SSIZE_MARIADB101 \
66 (FSP_FLAGS_POS_ATOMIC_WRITES_MARIADB101 + 2)
67
68/** Bit mask of the PAGE_COMPRESSION field */
69#define FSP_FLAGS_MASK_PAGE_COMPRESSION_MARIADB101 \
70 (1U << FSP_FLAGS_POS_PAGE_COMPRESSION_MARIADB101)
71/** Bit mask of the PAGE_COMPRESSION_LEVEL field */
72#define FSP_FLAGS_MASK_PAGE_COMPRESSION_LEVEL_MARIADB101 \
73 (15U << FSP_FLAGS_POS_PAGE_COMPRESSION_LEVEL_MARIADB101)
74/** Bit mask of the ATOMIC_WRITES field */
75#define FSP_FLAGS_MASK_ATOMIC_WRITES_MARIADB101 \
76 (3U << FSP_FLAGS_POS_ATOMIC_WRITES_MARIADB101)
77/** Bit mask of the PAGE_SSIZE field */
78#define FSP_FLAGS_MASK_PAGE_SSIZE_MARIADB101 \
79 (15U << FSP_FLAGS_POS_PAGE_SSIZE_MARIADB101)
80
81/** Return the value of the PAGE_COMPRESSION field */
82#define FSP_FLAGS_GET_PAGE_COMPRESSION_MARIADB101(flags) \
83 ((flags & FSP_FLAGS_MASK_PAGE_COMPRESSION_MARIADB101) \
84 >> FSP_FLAGS_POS_PAGE_COMPRESSION_MARIADB101)
85/** Return the value of the PAGE_COMPRESSION_LEVEL field */
86#define FSP_FLAGS_GET_PAGE_COMPRESSION_LEVEL_MARIADB101(flags) \
87 ((flags & FSP_FLAGS_MASK_PAGE_COMPRESSION_LEVEL_MARIADB101) \
88 >> FSP_FLAGS_POS_PAGE_COMPRESSION_LEVEL_MARIADB101)
89/** Return the value of the PAGE_SSIZE field */
90#define FSP_FLAGS_GET_PAGE_SSIZE_MARIADB101(flags) \
91 ((flags & FSP_FLAGS_MASK_PAGE_SSIZE_MARIADB101) \
92 >> FSP_FLAGS_POS_PAGE_SSIZE_MARIADB101)
93
94/* @} */
95
96/* @defgroup Tablespace Header Constants (moved from fsp0fsp.c) @{ */
97
98/** Offset of the space header within a file page */
99#define FSP_HEADER_OFFSET FIL_PAGE_DATA
100
101/* The data structures in files are defined just as byte strings in C */
102typedef byte fsp_header_t;
103typedef byte xdes_t;
104
105/* SPACE HEADER
106 ============
107
108File space header data structure: this data structure is contained in the
109first page of a space. The space for this header is reserved in every extent
110descriptor page, but used only in the first. */
111
112/*-------------------------------------*/
113#define FSP_SPACE_ID 0 /* space id */
114#define FSP_NOT_USED 4 /* this field contained a value up to
115 which we know that the modifications
116 in the database have been flushed to
117 the file space; not used now */
118#define FSP_SIZE 8 /* Current size of the space in
119 pages */
120#define FSP_FREE_LIMIT 12 /* Minimum page number for which the
121 free list has not been initialized:
122 the pages >= this limit are, by
123 definition, free; note that in a
124 single-table tablespace where size
125 < 64 pages, this number is 64, i.e.,
126 we have initialized the space
127 about the first extent, but have not
128 physically allocated those pages to the
129 file */
130#define FSP_SPACE_FLAGS 16 /* fsp_space_t.flags, similar to
131 dict_table_t::flags */
132#define FSP_FRAG_N_USED 20 /* number of used pages in the
133 FSP_FREE_FRAG list */
134#define FSP_FREE 24 /* list of free extents */
135#define FSP_FREE_FRAG (24 + FLST_BASE_NODE_SIZE)
136 /* list of partially free extents not
137 belonging to any segment */
138#define FSP_FULL_FRAG (24 + 2 * FLST_BASE_NODE_SIZE)
139 /* list of full extents not belonging
140 to any segment */
141#define FSP_SEG_ID (24 + 3 * FLST_BASE_NODE_SIZE)
142 /* 8 bytes which give the first unused
143 segment id */
144#define FSP_SEG_INODES_FULL (32 + 3 * FLST_BASE_NODE_SIZE)
145 /* list of pages containing segment
146 headers, where all the segment inode
147 slots are reserved */
148#define FSP_SEG_INODES_FREE (32 + 4 * FLST_BASE_NODE_SIZE)
149 /* list of pages containing segment
150 headers, where not all the segment
151 header slots are reserved */
152/*-------------------------------------*/
153/* File space header size */
154#define FSP_HEADER_SIZE (32 + 5 * FLST_BASE_NODE_SIZE)
155
156#define FSP_FREE_ADD 4 /* this many free extents are added
157 to the free list from above
158 FSP_FREE_LIMIT at a time */
159/* @} */
160
161/* @defgroup File Segment Inode Constants (moved from fsp0fsp.c) @{ */
162
163/* FILE SEGMENT INODE
164 ==================
165
166Segment inode which is created for each segment in a tablespace. NOTE: in
167purge we assume that a segment having only one currently used page can be
168freed in a few steps, so that the freeing cannot fill the file buffer with
169bufferfixed file pages. */
170
171typedef byte fseg_inode_t;
172
173#define FSEG_INODE_PAGE_NODE FSEG_PAGE_DATA
174 /* the list node for linking
175 segment inode pages */
176
177#define FSEG_ARR_OFFSET (FSEG_PAGE_DATA + FLST_NODE_SIZE)
178/*-------------------------------------*/
179#define FSEG_ID 0 /* 8 bytes of segment id: if this is 0,
180 it means that the header is unused */
181#define FSEG_NOT_FULL_N_USED 8
182 /* number of used segment pages in
183 the FSEG_NOT_FULL list */
184#define FSEG_FREE 12
185 /* list of free extents of this
186 segment */
187#define FSEG_NOT_FULL (12 + FLST_BASE_NODE_SIZE)
188 /* list of partially free extents */
189#define FSEG_FULL (12 + 2 * FLST_BASE_NODE_SIZE)
190 /* list of full extents */
191#define FSEG_MAGIC_N (12 + 3 * FLST_BASE_NODE_SIZE)
192 /* magic number used in debugging */
193#define FSEG_FRAG_ARR (16 + 3 * FLST_BASE_NODE_SIZE)
194 /* array of individual pages
195 belonging to this segment in fsp
196 fragment extent lists */
197#define FSEG_FRAG_ARR_N_SLOTS (FSP_EXTENT_SIZE / 2)
198 /* number of slots in the array for
199 the fragment pages */
200#define FSEG_FRAG_SLOT_SIZE 4 /* a fragment page slot contains its
201 page number within space, FIL_NULL
202 means that the slot is not in use */
203/*-------------------------------------*/
204#define FSEG_INODE_SIZE \
205 (16 + 3 * FLST_BASE_NODE_SIZE \
206 + FSEG_FRAG_ARR_N_SLOTS * FSEG_FRAG_SLOT_SIZE)
207
208#define FSP_SEG_INODES_PER_PAGE(page_size) \
209 ((page_size.physical() - FSEG_ARR_OFFSET - 10) / FSEG_INODE_SIZE)
210 /* Number of segment inodes which fit on a
211 single page */
212
213#define FSEG_MAGIC_N_VALUE 97937874
214
215#define FSEG_FILLFACTOR 8 /* If this value is x, then if
216 the number of unused but reserved
217 pages in a segment is less than
218 reserved pages * 1/x, and there are
219 at least FSEG_FRAG_LIMIT used pages,
220 then we allow a new empty extent to
221 be added to the segment in
222 fseg_alloc_free_page. Otherwise, we
223 use unused pages of the segment. */
224
225#define FSEG_FRAG_LIMIT FSEG_FRAG_ARR_N_SLOTS
226 /* If the segment has >= this many
227 used pages, it may be expanded by
228 allocating extents to the segment;
229 until that only individual fragment
230 pages are allocated from the space */
231
232#define FSEG_FREE_LIST_LIMIT 40 /* If the reserved size of a segment
233 is at least this many extents, we
234 allow extents to be put to the free
235 list of the extent: at most
236 FSEG_FREE_LIST_MAX_LEN many */
237#define FSEG_FREE_LIST_MAX_LEN 4
238/* @} */
239
240/* @defgroup Extent Descriptor Constants (moved from fsp0fsp.c) @{ */
241
242/* EXTENT DESCRIPTOR
243 =================
244
245File extent descriptor data structure: contains bits to tell which pages in
246the extent are free and which contain old tuple version to clean. */
247
248/*-------------------------------------*/
249#define XDES_ID 0 /* The identifier of the segment
250 to which this extent belongs */
251#define XDES_FLST_NODE 8 /* The list node data structure
252 for the descriptors */
253#define XDES_STATE (FLST_NODE_SIZE + 8)
254 /* contains state information
255 of the extent */
256#define XDES_BITMAP (FLST_NODE_SIZE + 12)
257 /* Descriptor bitmap of the pages
258 in the extent */
259/*-------------------------------------*/
260
261#define XDES_BITS_PER_PAGE 2 /* How many bits are there per page */
262#define XDES_FREE_BIT 0 /* Index of the bit which tells if
263 the page is free */
264#define XDES_CLEAN_BIT 1 /* NOTE: currently not used!
265 Index of the bit which tells if
266 there are old versions of tuples
267 on the page */
268/* States of a descriptor */
269#define XDES_FREE 1 /* extent is in free list of space */
270#define XDES_FREE_FRAG 2 /* extent is in free fragment list of
271 space */
272#define XDES_FULL_FRAG 3 /* extent is in full fragment list of
273 space */
274#define XDES_FSEG 4 /* extent belongs to a segment */
275
276/** File extent data structure size in bytes. */
277#define XDES_SIZE \
278 (XDES_BITMAP \
279 + UT_BITS_IN_BYTES(FSP_EXTENT_SIZE * XDES_BITS_PER_PAGE))
280
281/** File extent data structure size in bytes for MAX page size. */
282#define XDES_SIZE_MAX \
283 (XDES_BITMAP \
284 + UT_BITS_IN_BYTES(FSP_EXTENT_SIZE_MAX * XDES_BITS_PER_PAGE))
285
286/** File extent data structure size in bytes for MIN page size. */
287#define XDES_SIZE_MIN \
288 (XDES_BITMAP \
289 + UT_BITS_IN_BYTES(FSP_EXTENT_SIZE_MIN * XDES_BITS_PER_PAGE))
290
291/** Offset of the descriptor array on a descriptor page */
292#define XDES_ARR_OFFSET (FSP_HEADER_OFFSET + FSP_HEADER_SIZE)
293
294#ifndef UNIV_INNOCHECKSUM
295/* @} */
296
297/** Calculate the number of pages to extend a datafile.
298We extend single-table tablespaces first one extent at a time,
299but 4 at a time for bigger tablespaces. It is not enough to extend always
300by one extent, because we need to add at least one extent to FSP_FREE.
301A single extent descriptor page will track many extents. And the extent
302that uses its extent descriptor page is put onto the FSP_FREE_FRAG list.
303Extents that do not use their extent descriptor page are added to FSP_FREE.
304The physical page size is used to determine how many extents are tracked
305on one extent descriptor page. See xdes_calc_descriptor_page().
306@param[in] page_size page_size of the datafile
307@param[in] size current number of pages in the datafile
308@return number of pages to extend the file. */
309ulint
310fsp_get_pages_to_extend_ibd(
311 const page_size_t& page_size,
312 ulint size);
313
314/** Calculate the number of physical pages in an extent for this file.
315@param[in] page_size page_size of the datafile
316@return number of pages in an extent for this file. */
317UNIV_INLINE
318ulint
319fsp_get_extent_size_in_pages(const page_size_t& page_size)
320{
321 return (FSP_EXTENT_SIZE << srv_page_size_shift) / page_size.physical();
322}
323
324/**********************************************************************//**
325Reads the space id from the first page of a tablespace.
326@return space id, ULINT UNDEFINED if error */
327ulint
328fsp_header_get_space_id(
329/*====================*/
330 const page_t* page); /*!< in: first page of a tablespace */
331
332/** Read a tablespace header field.
333@param[in] page first page of a tablespace
334@param[in] field the header field
335@return the contents of the header field */
336inline
337ulint
338fsp_header_get_field(const page_t* page, ulint field)
339{
340 return(mach_read_from_4(FSP_HEADER_OFFSET + field + page));
341}
342
343/** Read the flags from the tablespace header page.
344@param[in] page first page of a tablespace
345@return the contents of FSP_SPACE_FLAGS */
346inline
347ulint
348fsp_header_get_flags(const page_t* page)
349{
350 return(fsp_header_get_field(page, FSP_SPACE_FLAGS));
351}
352
353/** Get the byte offset of encryption information in page 0.
354@param[in] ps page size
355@return byte offset relative to FSP_HEADER_OFFSET */
356inline MY_ATTRIBUTE((pure, warn_unused_result))
357ulint
358fsp_header_get_encryption_offset(const page_size_t& ps)
359{
360 return XDES_ARR_OFFSET + XDES_SIZE * ps.physical() / FSP_EXTENT_SIZE;
361}
362
363/** Check the encryption key from the first page of a tablespace.
364@param[in] fsp_flags tablespace flags
365@param[in] page first page of a tablespace
366@return true if success */
367bool
368fsp_header_check_encryption_key(
369 ulint fsp_flags,
370 page_t* page);
371
372/**********************************************************************//**
373Writes the space id and flags to a tablespace header. The flags contain
374row type, physical/compressed page size, and logical/uncompressed page
375size of the tablespace. */
376void
377fsp_header_init_fields(
378/*===================*/
379 page_t* page, /*!< in/out: first page in the space */
380 ulint space_id, /*!< in: space id */
381 ulint flags); /*!< in: tablespace flags (FSP_SPACE_FLAGS):
382 0, or table->flags if newer than COMPACT */
383/** Initialize a tablespace header.
384@param[in,out] space tablespace
385@param[in] size current size in blocks
386@param[in,out] mtr mini-transaction */
387void fsp_header_init(fil_space_t* space, ulint size, mtr_t* mtr)
388 MY_ATTRIBUTE((nonnull));
389
390/**********************************************************************//**
391Creates a new segment.
392@return the block where the segment header is placed, x-latched, NULL
393if could not create segment because of lack of space */
394buf_block_t*
395fseg_create(
396 fil_space_t* space, /*!< in,out: tablespace */
397 ulint page, /*!< in: page where the segment header is placed: if
398 this is != 0, the page must belong to another segment,
399 if this is 0, a new page will be allocated and it
400 will belong to the created segment */
401 ulint byte_offset, /*!< in: byte offset of the created segment header
402 on the page */
403 mtr_t* mtr,
404 bool has_done_reservation = false); /*!< in: whether the caller
405 has already done the reservation for the pages with
406 fsp_reserve_free_extents (at least 2 extents: one for
407 the inode and the other for the segment) then there is
408 no need to do the check for this individual
409 operation */
410
411/**********************************************************************//**
412Calculates the number of pages reserved by a segment, and how many pages are
413currently used.
414@return number of reserved pages */
415ulint
416fseg_n_reserved_pages(
417/*==================*/
418 fseg_header_t* header, /*!< in: segment header */
419 ulint* used, /*!< out: number of pages used (<= reserved) */
420 mtr_t* mtr); /*!< in/out: mini-transaction */
421/**********************************************************************//**
422Allocates a single free page from a segment. This function implements
423the intelligent allocation strategy which tries to minimize
424file space fragmentation.
425@param[in,out] seg_header segment header
426@param[in] hint hint of which page would be desirable
427@param[in] direction if the new page is needed because
428 of an index page split, and records are
429 inserted there in order, into which
430 direction they go alphabetically: FSP_DOWN,
431 FSP_UP, FSP_NO_DIR
432@param[in,out] mtr mini-transaction
433@return X-latched block, or NULL if no page could be allocated */
434#define fseg_alloc_free_page(seg_header, hint, direction, mtr) \
435 fseg_alloc_free_page_general(seg_header, hint, direction, \
436 FALSE, mtr, mtr)
437/**********************************************************************//**
438Allocates a single free page from a segment. This function implements
439the intelligent allocation strategy which tries to minimize file space
440fragmentation.
441@retval NULL if no page could be allocated
442@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
443(init_mtr == mtr, or the page was not previously freed in mtr)
444@retval block (not allocated or initialized) otherwise */
445buf_block_t*
446fseg_alloc_free_page_general(
447/*=========================*/
448 fseg_header_t* seg_header,/*!< in/out: segment header */
449 ulint hint, /*!< in: hint of which page would be
450 desirable */
451 byte direction,/*!< in: if the new page is needed because
452 of an index page split, and records are
453 inserted there in order, into which
454 direction they go alphabetically: FSP_DOWN,
455 FSP_UP, FSP_NO_DIR */
456 ibool has_done_reservation, /*!< in: TRUE if the caller has
457 already done the reservation for the page
458 with fsp_reserve_free_extents, then there
459 is no need to do the check for this individual
460 page */
461 mtr_t* mtr, /*!< in/out: mini-transaction */
462 mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction
463 in which the page should be initialized.
464 If init_mtr!=mtr, but the page is already
465 latched in mtr, do not initialize the page. */
466 MY_ATTRIBUTE((warn_unused_result, nonnull));
467
468/** Reserves free pages from a tablespace. All mini-transactions which may
469use several pages from the tablespace should call this function beforehand
470and reserve enough free extents so that they certainly will be able
471to do their operation, like a B-tree page split, fully. Reservations
472must be released with function fil_space_t::release_free_extents()!
473
474The alloc_type below has the following meaning: FSP_NORMAL means an
475operation which will probably result in more space usage, like an
476insert in a B-tree; FSP_UNDO means allocation to undo logs: if we are
477deleting rows, then this allocation will in the long run result in
478less space usage (after a purge); FSP_CLEANING means allocation done
479in a physical record delete (like in a purge) or other cleaning operation
480which will result in less space usage in the long run. We prefer the latter
481two types of allocation: when space is scarce, FSP_NORMAL allocations
482will not succeed, but the latter two allocations will succeed, if possible.
483The purpose is to avoid dead end where the database is full but the
484user cannot free any space because these freeing operations temporarily
485reserve some space.
486
487Single-table tablespaces whose size is < FSP_EXTENT_SIZE pages are a special
488case. In this function we would liberally reserve several extents for
489every page split or merge in a B-tree. But we do not want to waste disk space
490if the table only occupies < FSP_EXTENT_SIZE pages. That is why we apply
491different rules in that special case, just ensuring that there are n_pages
492free pages available.
493
494@param[out] n_reserved number of extents actually reserved; if we
495 return true and the tablespace size is <
496 FSP_EXTENT_SIZE pages, then this can be 0,
497 otherwise it is n_ext
498@param[in,out] space tablespace
499@param[in] n_ext number of extents to reserve
500@param[in] alloc_type page reservation type (FSP_BLOB, etc)
501@param[in,out] mtr the mini transaction
502@param[in] n_pages for small tablespaces (tablespace size is
503 less than FSP_EXTENT_SIZE), number of free
504 pages to reserve.
505@return true if we were able to make the reservation */
506bool
507fsp_reserve_free_extents(
508 ulint* n_reserved,
509 fil_space_t* space,
510 ulint n_ext,
511 fsp_reserve_t alloc_type,
512 mtr_t* mtr,
513 ulint n_pages = 2);
514
515/**********************************************************************//**
516Frees a single page of a segment. */
517void
518fseg_free_page_func(
519 fseg_header_t* seg_header, /*!< in: segment header */
520 ulint space_id, /*!< in: space id */
521 ulint page, /*!< in: page offset */
522#ifdef BTR_CUR_HASH_ADAPT
523 bool ahi, /*!< in: whether we may need to drop
524 the adaptive hash index */
525#endif /* BTR_CUR_HASH_ADAPT */
526 mtr_t* mtr); /*!< in/out: mini-transaction */
527#ifdef BTR_CUR_HASH_ADAPT
528# define fseg_free_page(header, space_id, page, ahi, mtr) \
529 fseg_free_page_func(header, space_id, page, ahi, mtr)
530#else /* BTR_CUR_HASH_ADAPT */
531# define fseg_free_page(header, space_id, page, ahi, mtr) \
532 fseg_free_page_func(header, space_id, page, mtr)
533#endif /* BTR_CUR_HASH_ADAPT */
534/** Determine whether a page is free.
535@param[in,out] space tablespace
536@param[in] page page number
537@return whether the page is marked as free */
538bool
539fseg_page_is_free(fil_space_t* space, unsigned page)
540 MY_ATTRIBUTE((nonnull, warn_unused_result));
541/**********************************************************************//**
542Frees part of a segment. This function can be used to free a segment
543by repeatedly calling this function in different mini-transactions.
544Doing the freeing in a single mini-transaction might result in
545too big a mini-transaction.
546@return TRUE if freeing completed */
547ibool
548fseg_free_step_func(
549 fseg_header_t* header, /*!< in, own: segment header; NOTE: if the header
550 resides on the first page of the frag list
551 of the segment, this pointer becomes obsolete
552 after the last freeing step */
553#ifdef BTR_CUR_HASH_ADAPT
554 bool ahi, /*!< in: whether we may need to drop
555 the adaptive hash index */
556#endif /* BTR_CUR_HASH_ADAPT */
557 mtr_t* mtr) /*!< in/out: mini-transaction */
558 MY_ATTRIBUTE((warn_unused_result));
559#ifdef BTR_CUR_HASH_ADAPT
560# define fseg_free_step(header, ahi, mtr) fseg_free_step_func(header, ahi, mtr)
561#else /* BTR_CUR_HASH_ADAPT */
562# define fseg_free_step(header, ahi, mtr) fseg_free_step_func(header, mtr)
563#endif /* BTR_CUR_HASH_ADAPT */
564/**********************************************************************//**
565Frees part of a segment. Differs from fseg_free_step because this function
566leaves the header page unfreed.
567@return TRUE if freeing completed, except the header page */
568ibool
569fseg_free_step_not_header_func(
570 fseg_header_t* header, /*!< in: segment header which must reside on
571 the first fragment page of the segment */
572#ifdef BTR_CUR_HASH_ADAPT
573 bool ahi, /*!< in: whether we may need to drop
574 the adaptive hash index */
575#endif /* BTR_CUR_HASH_ADAPT */
576 mtr_t* mtr) /*!< in/out: mini-transaction */
577 MY_ATTRIBUTE((warn_unused_result));
578#ifdef BTR_CUR_HASH_ADAPT
579# define fseg_free_step_not_header(header, ahi, mtr) \
580 fseg_free_step_not_header_func(header, ahi, mtr)
581#else /* BTR_CUR_HASH_ADAPT */
582# define fseg_free_step_not_header(header, ahi, mtr) \
583 fseg_free_step_not_header_func(header, mtr)
584#endif /* BTR_CUR_HASH_ADAPT */
585
586/** Checks if a page address is an extent descriptor page address.
587@param[in] page_id page id
588@param[in] page_size page size
589@return TRUE if a descriptor page */
590UNIV_INLINE
591ibool
592fsp_descr_page(
593 const page_id_t& page_id,
594 const page_size_t& page_size);
595
596/***********************************************************//**
597Parses a redo log record of a file page init.
598@return end of log record or NULL */
599byte*
600fsp_parse_init_file_page(
601/*=====================*/
602 byte* ptr, /*!< in: buffer */
603 byte* end_ptr, /*!< in: buffer end */
604 buf_block_t* block); /*!< in: block or NULL */
605#ifdef UNIV_BTR_PRINT
606/*******************************************************************//**
607Writes info of a segment. */
608void
609fseg_print(
610/*=======*/
611 fseg_header_t* header, /*!< in: segment header */
612 mtr_t* mtr); /*!< in/out: mini-transaction */
613#endif /* UNIV_BTR_PRINT */
614
615/** Convert FSP_SPACE_FLAGS from the buggy MariaDB 10.1.0..10.1.20 format.
616@param[in] flags the contents of FSP_SPACE_FLAGS
617@return the flags corrected from the buggy MariaDB 10.1 format
618@retval ULINT_UNDEFINED if the flags are not in the buggy 10.1 format */
619MY_ATTRIBUTE((warn_unused_result, const))
620UNIV_INLINE
621ulint
622fsp_flags_convert_from_101(ulint flags)
623{
624 DBUG_EXECUTE_IF("fsp_flags_is_valid_failure",
625 return(ULINT_UNDEFINED););
626 if (flags == 0) {
627 return(flags);
628 }
629
630 if (flags >> 18) {
631 /* The most significant FSP_SPACE_FLAGS bit that was ever set
632 by MariaDB 10.1.0 to 10.1.20 was bit 17 (misplaced DATA_DIR flag).
633 The flags must be less than 1<<18 in order to be valid. */
634 return(ULINT_UNDEFINED);
635 }
636
637 if ((flags & (FSP_FLAGS_MASK_POST_ANTELOPE | FSP_FLAGS_MASK_ATOMIC_BLOBS))
638 == FSP_FLAGS_MASK_ATOMIC_BLOBS) {
639 /* If the "atomic blobs" flag (indicating
640 ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED) flag
641 is set, then the "post Antelope" (ROW_FORMAT!=REDUNDANT) flag
642 must also be set. */
643 return(ULINT_UNDEFINED);
644 }
645
646 /* Bits 6..10 denote compression in MariaDB 10.1.0 to 10.1.20.
647 They must be either 0b00000 or 0b00011 through 0b10011.
648 In correct versions, these bits would be
649 0bd0sss where d is the DATA_DIR flag (garbage bit) and
650 sss is the PAGE_SSIZE (3, 4, 6, or 7).
651
652 NOTE: MariaDB 10.1.0 to 10.1.20 can misinterpret
653 uncompressed data files with innodb_page_size=4k or 64k as
654 compressed innodb_page_size=16k files. Below is an exhaustive
655 state space analysis.
656
657 -0by1zzz: impossible (the bit 4 must be clean; see above)
658 -0b101xx: DATA_DIR, innodb_page_size>4k: invalid (COMPRESSION_LEVEL>9)
659 +0bx0011: innodb_page_size=4k:
660 !!! Misinterpreted as COMPRESSION_LEVEL=9 or 1, COMPRESSION=1.
661 -0bx0010: impossible, because sss must be 0b011 or 0b1xx
662 -0bx0001: impossible, because sss must be 0b011 or 0b1xx
663 -0b10000: DATA_DIR, innodb_page_size=16:
664 invalid (COMPRESSION_LEVEL=8 but COMPRESSION=0)
665 +0b00111: no DATA_DIR, innodb_page_size=64k:
666 !!! Misinterpreted as COMPRESSION_LEVEL=3, COMPRESSION=1.
667 -0b00101: impossible, because sss must be 0 for 16k, not 0b101
668 -0b001x0: no DATA_DIR, innodb_page_size=32k or 8k:
669 invalid (COMPRESSION_LEVEL=3 but COMPRESSION=0)
670 +0b00000: innodb_page_size=16k (looks like COMPRESSION=0)
671 ??? Could actually be compressed; see PAGE_SSIZE below */
672 const ulint level = FSP_FLAGS_GET_PAGE_COMPRESSION_LEVEL_MARIADB101(
673 flags);
674 if (FSP_FLAGS_GET_PAGE_COMPRESSION_MARIADB101(flags) != (level != 0)
675 || level > 9) {
676 /* The compression flags are not in the buggy MariaDB
677 10.1 format. */
678 return(ULINT_UNDEFINED);
679 }
680 if (!(~flags & FSP_FLAGS_MASK_ATOMIC_WRITES_MARIADB101)) {
681 /* The ATOMIC_WRITES flags cannot be 0b11.
682 (The bits 11..12 should actually never be 0b11,
683 because in MySQL they would be SHARED|TEMPORARY.) */
684 return(ULINT_UNDEFINED);
685 }
686
687 /* Bits 13..16 are the wrong position for PAGE_SSIZE, and they
688 should contain one of the values 3,4,6,7, that is, be of the form
689 0b0011 or 0b01xx (except 0b0110).
690 In correct versions, these bits should be 0bc0se
691 where c is the MariaDB COMPRESSED flag
692 and e is the MySQL 5.7 ENCRYPTION flag
693 and s is the MySQL 8.0 SDI flag. MariaDB can only support s=0, e=0.
694
695 Compressed innodb_page_size=16k tables with correct FSP_SPACE_FLAGS
696 will be properly rejected by older MariaDB 10.1.x because they
697 would read as PAGE_SSIZE>=8 which is not valid. */
698
699 const ulint ssize = FSP_FLAGS_GET_PAGE_SSIZE_MARIADB101(flags);
700 if (ssize == 1 || ssize == 2 || ssize == 5 || ssize & 8) {
701 /* the page_size is not between 4k and 64k;
702 16k should be encoded as 0, not 5 */
703 return(ULINT_UNDEFINED);
704 }
705 const ulint zssize = FSP_FLAGS_GET_ZIP_SSIZE(flags);
706 if (zssize == 0) {
707 /* not ROW_FORMAT=COMPRESSED */
708 } else if (zssize > (ssize ? ssize : 5)) {
709 /* invalid KEY_BLOCK_SIZE */
710 return(ULINT_UNDEFINED);
711 } else if (~flags & (FSP_FLAGS_MASK_POST_ANTELOPE
712 | FSP_FLAGS_MASK_ATOMIC_BLOBS)) {
713 /* both these flags should be set for
714 ROW_FORMAT=COMPRESSED */
715 return(ULINT_UNDEFINED);
716 }
717
718 flags = ((flags & 0x3f) | ssize << FSP_FLAGS_POS_PAGE_SSIZE
719 | FSP_FLAGS_GET_PAGE_COMPRESSION_MARIADB101(flags)
720 << FSP_FLAGS_POS_PAGE_COMPRESSION);
721 ut_ad(fsp_flags_is_valid(flags, false));
722 return(flags);
723}
724
725/** Compare tablespace flags.
726@param[in] expected expected flags from dict_tf_to_fsp_flags()
727@param[in] actual flags read from FSP_SPACE_FLAGS
728@return whether the flags match */
729MY_ATTRIBUTE((warn_unused_result))
730UNIV_INLINE
731bool
732fsp_flags_match(ulint expected, ulint actual)
733{
734 expected &= ~FSP_FLAGS_MEM_MASK;
735 ut_ad(fsp_flags_is_valid(expected, false));
736
737 if (actual == expected) {
738 return(true);
739 }
740
741 actual = fsp_flags_convert_from_101(actual);
742 return(actual == expected);
743}
744
745/** Calculates the descriptor index within a descriptor page.
746@param[in] page_size page size
747@param[in] offset page offset
748@return descriptor index */
749UNIV_INLINE
750ulint
751xdes_calc_descriptor_index(
752 const page_size_t& page_size,
753 ulint offset);
754
755/**********************************************************************//**
756Gets a descriptor bit of a page.
757@return TRUE if free */
758UNIV_INLINE
759ibool
760xdes_get_bit(
761/*=========*/
762 const xdes_t* descr, /*!< in: descriptor */
763 ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
764 ulint offset);/*!< in: page offset within extent:
765 0 ... FSP_EXTENT_SIZE - 1 */
766
767/** Calculates the page where the descriptor of a page resides.
768@param[in] page_size page size
769@param[in] offset page offset
770@return descriptor page offset */
771UNIV_INLINE
772ulint
773xdes_calc_descriptor_page(
774 const page_size_t& page_size,
775 ulint offset);
776
777#endif /* UNIV_INNOCHECKSUM */
778
779#include "fsp0fsp.ic"
780
781#endif
782