1/*****************************************************************************
2
3Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
4
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License, version 2.0,
7as published by the Free Software Foundation.
8
9This program is also distributed with certain software (including
10but not limited to OpenSSL) that is licensed under separate terms,
11as designated in a particular file or component or in included license
12documentation.  The authors of MySQL hereby grant you an additional
13permission to link the program and your derivative works with the
14separately licensed software that they have included with MySQL.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19GNU General Public License, version 2.0, for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc.,
2351 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24
25*****************************************************************************/
26
27/**************************************************//**
28@file include/fsp0fsp.ic
29File space management
30
31Created 12/18/1995 Heikki Tuuri
32*******************************************************/
33
34#ifndef UNIV_INNOCHECKSUM
35
36/***********************************************************************//**
37Checks if a page address is an extent descriptor page address.
38@return	TRUE if a descriptor page */
39UNIV_INLINE
40ibool
41fsp_descr_page(
42/*===========*/
43	ulint	zip_size,/*!< in: compressed page size in bytes;
44			0 for uncompressed pages */
45	ulint	page_no)/*!< in: page number */
46{
47	ut_ad(ut_is_2pow(zip_size));
48
49	if (!zip_size) {
50		return((page_no & (UNIV_PAGE_SIZE - 1)) == FSP_XDES_OFFSET);
51	}
52
53	return((page_no & (zip_size - 1)) == FSP_XDES_OFFSET);
54}
55
56/********************************************************************//**
57Validate and return the tablespace flags, which are stored in the
58tablespace header at offset FSP_SPACE_FLAGS.  They should be 0 for
59ROW_FORMAT=COMPACT and ROW_FORMAT=REDUNDANT. The newer row formats,
60COMPRESSED and DYNAMIC, use a file format > Antelope so they should
61have a file format number plus the DICT_TF_COMPACT bit set.
62@return	true if check ok */
63UNIV_INLINE
64bool
65fsp_flags_is_valid(
66/*===============*/
67	ulint	flags)		/*!< in: tablespace flags */
68{
69	ulint	post_antelope = FSP_FLAGS_GET_POST_ANTELOPE(flags);
70	ulint	zip_ssize = FSP_FLAGS_GET_ZIP_SSIZE(flags);
71	ulint	atomic_blobs = FSP_FLAGS_HAS_ATOMIC_BLOBS(flags);
72	ulint	page_ssize = FSP_FLAGS_GET_PAGE_SSIZE(flags);
73	ulint	unused = FSP_FLAGS_GET_UNUSED(flags);
74
75	DBUG_EXECUTE_IF("fsp_flags_is_valid_failure", return(false););
76
77	/* fsp_flags is zero unless atomic_blobs is set. */
78	/* Make sure there are no bits that we do not know about. */
79	if (unused != 0 || flags == 1) {
80		return(false);
81	} else if (post_antelope) {
82		/* The Antelope row formats REDUNDANT and COMPACT did
83		not use tablespace flags, so this flag and the entire
84		4-byte field is zero for Antelope row formats. */
85
86		if (!atomic_blobs) {
87			return(false);
88		}
89	}
90
91	if (!atomic_blobs) {
92		/* Barracuda row formats COMPRESSED and DYNAMIC build on
93		the page structure introduced for the COMPACT row format
94		by allowing long fields to be broken into prefix and
95		externally stored parts. */
96
97		if (post_antelope || zip_ssize != 0) {
98			return(false);
99		}
100
101	} else if (!post_antelope || zip_ssize > PAGE_ZIP_SSIZE_MAX) {
102		return(false);
103	} else if (page_ssize > UNIV_PAGE_SSIZE_MAX) {
104
105		/* The page size field can be used for any row type, or it may
106		be zero for an original 16k page size.
107		Validate the page shift size is within allowed range. */
108
109		return(false);
110
111	} else if (UNIV_PAGE_SIZE != UNIV_PAGE_SIZE_ORIG && !page_ssize) {
112		return(false);
113	}
114
115#if UNIV_FORMAT_MAX != UNIV_FORMAT_B
116# error "UNIV_FORMAT_MAX != UNIV_FORMAT_B, Add more validations."
117#endif
118
119	/* The DATA_DIR field can be used for any row type so there is
120	nothing here to validate. */
121
122	return(true);
123}
124
125/********************************************************************//**
126Determine if the tablespace is compressed from dict_table_t::flags.
127@return	TRUE if compressed, FALSE if not compressed */
128UNIV_INLINE
129ibool
130fsp_flags_is_compressed(
131/*====================*/
132	ulint	flags)	/*!< in: tablespace flags */
133{
134	return(FSP_FLAGS_GET_ZIP_SSIZE(flags) != 0);
135}
136
137#endif /* !UNIV_INNOCHECKSUM */
138
139/********************************************************************//**
140Extract the zip size from tablespace flags.
141@return	compressed page size of the file-per-table tablespace in bytes,
142or zero if the table is not compressed. */
143UNIV_INLINE
144ulint
145fsp_flags_get_zip_size(
146/*===================*/
147	ulint	flags)	/*!< in: tablespace flags */
148{
149	ulint	zip_size = 0;
150	ulint	ssize = FSP_FLAGS_GET_ZIP_SSIZE(flags);
151
152	/* Convert from a 'log2 minus 9' to a page size in bytes. */
153	if (ssize) {
154		zip_size = ((UNIV_ZIP_SIZE_MIN >> 1) << ssize);
155
156		ut_ad(zip_size <= UNIV_ZIP_SIZE_MAX);
157	}
158
159	return(zip_size);
160}
161
162/********************************************************************//**
163Extract the page size from tablespace flags.
164@return	page size of the tablespace in bytes */
165UNIV_INLINE
166ulint
167fsp_flags_get_page_size(
168/*====================*/
169	ulint	flags)	/*!< in: tablespace flags */
170{
171	ulint	page_size = 0;
172	ulint	ssize = FSP_FLAGS_GET_PAGE_SSIZE(flags);
173
174	/* Convert from a 'log2 minus 9' to a page size in bytes. */
175	if (UNIV_UNLIKELY(ssize)) {
176		page_size = ((UNIV_ZIP_SIZE_MIN >> 1) << ssize);
177
178		ut_ad(page_size <= UNIV_PAGE_SIZE_MAX);
179	} else {
180		/* If the page size was not stored, then it is the
181		original 16k. */
182		page_size = UNIV_PAGE_SIZE_ORIG;
183	}
184
185	return(page_size);
186}
187
188#ifndef UNIV_INNOCHECKSUM
189
190/********************************************************************//**
191Add the page size to the tablespace flags.
192@return	tablespace flags after page size is added */
193UNIV_INLINE
194ulint
195fsp_flags_set_page_size(
196/*====================*/
197	ulint	flags,		/*!< in: tablespace flags */
198	ulint	page_size)	/*!< in: page size in bytes */
199{
200	ulint ssize = 0;
201	ulint shift;
202
203	/* Page size should be > UNIV_PAGE_SIZE_MIN */
204	ut_ad(page_size >= UNIV_PAGE_SIZE_MIN);
205	ut_ad(page_size <= UNIV_PAGE_SIZE_MAX);
206
207	if (page_size == UNIV_PAGE_SIZE_ORIG) {
208		ut_ad(0 == FSP_FLAGS_GET_PAGE_SSIZE(flags));
209		return(flags);
210	}
211
212	for (shift = UNIV_PAGE_SIZE_SHIFT_MAX;
213	     shift >= UNIV_PAGE_SIZE_SHIFT_MIN;
214	     shift--) {
215		ulint	mask = (1 << shift);
216		if (page_size & mask) {
217			ut_ad(!(page_size & ~mask));
218			ssize = shift - UNIV_ZIP_SIZE_SHIFT_MIN + 1;
219			break;
220		}
221	}
222
223	ut_ad(ssize);
224	ut_ad(ssize <= UNIV_PAGE_SSIZE_MAX);
225
226	flags = FSP_FLAGS_SET_PAGE_SSIZE(flags, ssize);
227
228	ut_ad(fsp_flags_is_valid(flags));
229
230	return(flags);
231}
232
233/********************************************************************//**
234Calculates the descriptor index within a descriptor page.
235@return	descriptor index */
236UNIV_INLINE
237ulint
238xdes_calc_descriptor_index(
239/*=======================*/
240	ulint	zip_size,	/*!< in: compressed page size in bytes;
241				0 for uncompressed pages */
242	ulint	offset)		/*!< in: page offset */
243{
244	ut_ad(ut_is_2pow(zip_size));
245
246	if (zip_size == 0) {
247		return(ut_2pow_remainder(offset, UNIV_PAGE_SIZE)
248		       / FSP_EXTENT_SIZE);
249	} else {
250		return(ut_2pow_remainder(offset, zip_size) / FSP_EXTENT_SIZE);
251	}
252}
253
254/**********************************************************************//**
255Gets a descriptor bit of a page.
256@return	TRUE if free */
257UNIV_INLINE
258ibool
259xdes_get_bit(
260/*=========*/
261	const xdes_t*	descr,	/*!< in: descriptor */
262	ulint		bit,	/*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */
263	ulint		offset)	/*!< in: page offset within extent:
264				0 ... FSP_EXTENT_SIZE - 1 */
265{
266	ut_ad(offset < FSP_EXTENT_SIZE);
267	ut_ad(bit == XDES_FREE_BIT || bit == XDES_CLEAN_BIT);
268
269	ulint	index = bit + XDES_BITS_PER_PAGE * offset;
270
271	ulint	bit_index = index % 8;
272	ulint	byte_index = index / 8;
273
274	return(ut_bit_get_nth(
275			mach_read_ulint(descr + XDES_BITMAP + byte_index,
276					MLOG_1BYTE),
277			bit_index));
278}
279
280/********************************************************************//**
281Calculates the page where the descriptor of a page resides.
282@return	descriptor page offset */
283UNIV_INLINE
284ulint
285xdes_calc_descriptor_page(
286/*======================*/
287	ulint	zip_size,	/*!< in: compressed page size in bytes;
288				0 for uncompressed pages */
289	ulint	offset)		/*!< in: page offset */
290{
291#ifndef DOXYGEN /* Doxygen gets confused by these */
292# if UNIV_PAGE_SIZE_MAX <= XDES_ARR_OFFSET				\
293			   + (UNIV_PAGE_SIZE_MAX / FSP_EXTENT_SIZE_MAX)	\
294			   * XDES_SIZE_MAX
295#  error
296# endif
297# if UNIV_ZIP_SIZE_MIN <= XDES_ARR_OFFSET				\
298			  + (UNIV_ZIP_SIZE_MIN / FSP_EXTENT_SIZE_MIN)	\
299			  * XDES_SIZE_MIN
300#  error
301# endif
302#endif /* !DOXYGEN */
303
304	ut_ad(UNIV_PAGE_SIZE > XDES_ARR_OFFSET
305	      + (UNIV_PAGE_SIZE / FSP_EXTENT_SIZE)
306	      * XDES_SIZE);
307	ut_ad(UNIV_ZIP_SIZE_MIN > XDES_ARR_OFFSET
308	      + (UNIV_ZIP_SIZE_MIN / FSP_EXTENT_SIZE)
309	      * XDES_SIZE);
310
311	ut_ad(ut_is_2pow(zip_size));
312
313	if (zip_size == 0) {
314		return(ut_2pow_round(offset, UNIV_PAGE_SIZE));
315	} else {
316		ut_ad(zip_size > XDES_ARR_OFFSET
317		      + (zip_size / FSP_EXTENT_SIZE) * XDES_SIZE);
318		return(ut_2pow_round(offset, zip_size));
319	}
320}
321
322#endif /* !UNIV_INNOCHECKSUM */
323