~drizzle-trunk/drizzle/development

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