1/*****************************************************************************
2
3Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2008, Google Inc.
5
6Portions of this file contain modifications contributed and copyrighted by
7Google, Inc. Those modifications are gratefully acknowledged and are described
8briefly in the InnoDB documentation. The contributions by Google are
9incorporated with their permission, and subject to the conditions contained in
10the file COPYING.Google.
11
12This program is free software; you can redistribute it and/or modify
13it under the terms of the GNU General Public License, version 2.0,
14as published by the Free Software Foundation.
15
16This program is also distributed with certain software (including
17but not limited to OpenSSL) that is licensed under separate terms,
18as designated in a particular file or component or in included license
19documentation.  The authors of MySQL hereby grant you an additional
20permission to link the program and your derivative works with the
21separately licensed software that they have included with MySQL.
22
23This program is distributed in the hope that it will be useful,
24but WITHOUT ANY WARRANTY; without even the implied warranty of
25MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26GNU General Public License, version 2.0, for more details.
27
28You should have received a copy of the GNU General Public License along with
29this program; if not, write to the Free Software Foundation, Inc.,
3051 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
31
32*****************************************************************************/
33
34/**************************************************//**
35@file include/buf0buf.ic
36The database buffer buf_pool
37
38Created 11/5/1995 Heikki Tuuri
39*******************************************************/
40
41#include "mtr0mtr.h"
42#ifndef UNIV_HOTBACKUP
43#include "buf0flu.h"
44#include "buf0lru.h"
45#include "buf0rea.h"
46
47/** A chunk of buffers. The buffer pool is allocated in chunks. */
48struct buf_chunk_t{
49	ulint		mem_size;	/*!< allocated size of the chunk */
50	ulint		size;		/*!< size of frames[] and blocks[] */
51	void*		mem;		/*!< pointer to the memory area which
52					was allocated for the frames */
53	buf_block_t*	blocks;		/*!< array of buffer control blocks */
54};
55
56/*********************************************************************//**
57Gets the current size of buffer buf_pool in bytes.
58@return size in bytes */
59UNIV_INLINE
60ulint
61buf_pool_get_curr_size(void)
62/*========================*/
63{
64	return(srv_buf_pool_curr_size);
65}
66
67/********************************************************************//**
68Calculates the index of a buffer pool to the buf_pool[] array.
69@return	the position of the buffer pool in buf_pool[] */
70UNIV_INLINE
71ulint
72buf_pool_index(
73/*===========*/
74	const buf_pool_t*	buf_pool)	/*!< in: buffer pool */
75{
76	ulint	i = buf_pool - buf_pool_ptr;
77	ut_ad(i < MAX_BUFFER_POOLS);
78	ut_ad(i < srv_buf_pool_instances);
79	return(i);
80}
81
82/******************************************************************//**
83Returns the buffer pool instance given a page instance
84@return buf_pool */
85UNIV_INLINE
86buf_pool_t*
87buf_pool_from_bpage(
88/*================*/
89	const buf_page_t*	bpage) /*!< in: buffer pool page */
90{
91	ulint	i;
92	i = bpage->buf_pool_index;
93	ut_ad(i < srv_buf_pool_instances);
94	return(&buf_pool_ptr[i]);
95}
96
97/******************************************************************//**
98Returns the buffer pool instance given a block instance
99@return buf_pool */
100UNIV_INLINE
101buf_pool_t*
102buf_pool_from_block(
103/*================*/
104	const buf_block_t*	block) /*!< in: block */
105{
106	return(buf_pool_from_bpage(&block->page));
107}
108
109/*********************************************************************//**
110Gets the current size of buffer buf_pool in pages.
111@return size in pages*/
112UNIV_INLINE
113ulint
114buf_pool_get_n_pages(void)
115/*======================*/
116{
117	return(buf_pool_get_curr_size() / UNIV_PAGE_SIZE);
118}
119
120/********************************************************************//**
121Reads the freed_page_clock of a buffer block.
122@return	freed_page_clock */
123UNIV_INLINE
124ulint
125buf_page_get_freed_page_clock(
126/*==========================*/
127	const buf_page_t*	bpage)	/*!< in: block */
128{
129	/* This is sometimes read without holding buf_pool->mutex. */
130	return(bpage->freed_page_clock);
131}
132
133/********************************************************************//**
134Reads the freed_page_clock of a buffer block.
135@return	freed_page_clock */
136UNIV_INLINE
137ulint
138buf_block_get_freed_page_clock(
139/*===========================*/
140	const buf_block_t*	block)	/*!< in: block */
141{
142	return(buf_page_get_freed_page_clock(&block->page));
143}
144
145/********************************************************************//**
146Tells if a block is still close enough to the MRU end of the LRU list
147meaning that it is not in danger of getting evicted and also implying
148that it has been accessed recently.
149Note that this is for heuristics only and does not reserve buffer pool
150mutex.
151@return	TRUE if block is close to MRU end of LRU */
152UNIV_INLINE
153ibool
154buf_page_peek_if_young(
155/*===================*/
156	const buf_page_t*	bpage)	/*!< in: block */
157{
158	buf_pool_t*	buf_pool = buf_pool_from_bpage(bpage);
159
160	/* FIXME: bpage->freed_page_clock is 31 bits */
161	return((buf_pool->freed_page_clock & ((1UL << 31) - 1))
162	       < ((ulint) bpage->freed_page_clock
163		  + (buf_pool->curr_size
164		     * (BUF_LRU_OLD_RATIO_DIV - buf_pool->LRU_old_ratio)
165		     / (BUF_LRU_OLD_RATIO_DIV * 4))));
166}
167
168/********************************************************************//**
169Recommends a move of a block to the start of the LRU list if there is danger
170of dropping from the buffer pool. NOTE: does not reserve the buffer pool
171mutex.
172@return	TRUE if should be made younger */
173UNIV_INLINE
174ibool
175buf_page_peek_if_too_old(
176/*=====================*/
177	const buf_page_t*	bpage)	/*!< in: block to make younger */
178{
179	buf_pool_t*		buf_pool = buf_pool_from_bpage(bpage);
180
181	if (buf_pool->freed_page_clock == 0) {
182		/* If eviction has not started yet, do not update the
183		statistics or move blocks in the LRU list.  This is
184		either the warm-up phase or an in-memory workload. */
185		return(FALSE);
186	} else if (buf_LRU_old_threshold_ms && bpage->old) {
187		unsigned	access_time = buf_page_is_accessed(bpage);
188
189		if (access_time > 0
190		    && ((ib_uint32_t) (ut_time_ms() - access_time))
191		    >= buf_LRU_old_threshold_ms) {
192			return(TRUE);
193		}
194
195		buf_pool->stat.n_pages_not_made_young++;
196		return(FALSE);
197	} else {
198		return(!buf_page_peek_if_young(bpage));
199	}
200}
201#endif /* !UNIV_HOTBACKUP */
202
203/*********************************************************************//**
204Gets the state of a block.
205@return	state */
206UNIV_INLINE
207enum buf_page_state
208buf_page_get_state(
209/*===============*/
210	const buf_page_t*	bpage)	/*!< in: pointer to the control block */
211{
212	enum buf_page_state	state = (enum buf_page_state) bpage->state;
213
214#ifdef UNIV_DEBUG
215	switch (state) {
216	case BUF_BLOCK_POOL_WATCH:
217	case BUF_BLOCK_ZIP_PAGE:
218	case BUF_BLOCK_ZIP_DIRTY:
219	case BUF_BLOCK_NOT_USED:
220	case BUF_BLOCK_READY_FOR_USE:
221	case BUF_BLOCK_FILE_PAGE:
222	case BUF_BLOCK_MEMORY:
223	case BUF_BLOCK_REMOVE_HASH:
224		break;
225	default:
226		ut_error;
227	}
228#endif /* UNIV_DEBUG */
229
230	return(state);
231}
232/*********************************************************************//**
233Gets the state of a block.
234@return	state */
235UNIV_INLINE
236enum buf_page_state
237buf_block_get_state(
238/*================*/
239	const buf_block_t*	block)	/*!< in: pointer to the control block */
240{
241	return(buf_page_get_state(&block->page));
242}
243/*********************************************************************//**
244Sets the state of a block. */
245UNIV_INLINE
246void
247buf_page_set_state(
248/*===============*/
249	buf_page_t*		bpage,	/*!< in/out: pointer to control block */
250	enum buf_page_state	state)	/*!< in: state */
251{
252#ifdef UNIV_DEBUG
253	enum buf_page_state	old_state	= buf_page_get_state(bpage);
254
255	switch (old_state) {
256	case BUF_BLOCK_POOL_WATCH:
257		ut_error;
258		break;
259	case BUF_BLOCK_ZIP_PAGE:
260		ut_a(state == BUF_BLOCK_ZIP_DIRTY);
261		break;
262	case BUF_BLOCK_ZIP_DIRTY:
263		ut_a(state == BUF_BLOCK_ZIP_PAGE);
264		break;
265	case BUF_BLOCK_NOT_USED:
266		ut_a(state == BUF_BLOCK_READY_FOR_USE);
267		break;
268	case BUF_BLOCK_READY_FOR_USE:
269		ut_a(state == BUF_BLOCK_MEMORY
270		     || state == BUF_BLOCK_FILE_PAGE
271		     || state == BUF_BLOCK_NOT_USED);
272		break;
273	case BUF_BLOCK_MEMORY:
274		ut_a(state == BUF_BLOCK_NOT_USED);
275		break;
276	case BUF_BLOCK_FILE_PAGE:
277		ut_a(state == BUF_BLOCK_NOT_USED
278		     || state == BUF_BLOCK_REMOVE_HASH);
279		break;
280	case BUF_BLOCK_REMOVE_HASH:
281		ut_a(state == BUF_BLOCK_MEMORY);
282		break;
283	}
284#endif /* UNIV_DEBUG */
285	bpage->state = state;
286	ut_ad(buf_page_get_state(bpage) == state);
287}
288
289/*********************************************************************//**
290Sets the state of a block. */
291UNIV_INLINE
292void
293buf_block_set_state(
294/*================*/
295	buf_block_t*		block,	/*!< in/out: pointer to control block */
296	enum buf_page_state	state)	/*!< in: state */
297{
298	buf_page_set_state(&block->page, state);
299}
300
301/*********************************************************************//**
302Determines if a block is mapped to a tablespace.
303@return	TRUE if mapped */
304UNIV_INLINE
305ibool
306buf_page_in_file(
307/*=============*/
308	const buf_page_t*	bpage)	/*!< in: pointer to control block */
309{
310	switch (buf_page_get_state(bpage)) {
311	case BUF_BLOCK_POOL_WATCH:
312		ut_error;
313		break;
314	case BUF_BLOCK_ZIP_PAGE:
315	case BUF_BLOCK_ZIP_DIRTY:
316	case BUF_BLOCK_FILE_PAGE:
317		return(TRUE);
318	case BUF_BLOCK_NOT_USED:
319	case BUF_BLOCK_READY_FOR_USE:
320	case BUF_BLOCK_MEMORY:
321	case BUF_BLOCK_REMOVE_HASH:
322		break;
323	}
324
325	return(FALSE);
326}
327
328#ifndef UNIV_HOTBACKUP
329/*********************************************************************//**
330Determines if a block should be on unzip_LRU list.
331@return	TRUE if block belongs to unzip_LRU */
332UNIV_INLINE
333ibool
334buf_page_belongs_to_unzip_LRU(
335/*==========================*/
336	const buf_page_t*	bpage)	/*!< in: pointer to control block */
337{
338	ut_ad(buf_page_in_file(bpage));
339
340	return(bpage->zip.data
341	       && buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE);
342}
343
344/*********************************************************************//**
345Gets the mutex of a block.
346@return	pointer to mutex protecting bpage */
347UNIV_INLINE
348ib_mutex_t*
349buf_page_get_mutex(
350/*===============*/
351	const buf_page_t*	bpage)	/*!< in: pointer to control block */
352{
353	switch (buf_page_get_state(bpage)) {
354	case BUF_BLOCK_POOL_WATCH:
355		ut_error;
356		return(NULL);
357	case BUF_BLOCK_ZIP_PAGE:
358	case BUF_BLOCK_ZIP_DIRTY: {
359		buf_pool_t*	buf_pool = buf_pool_from_bpage(bpage);
360
361		return(&buf_pool->zip_mutex);
362		}
363	default:
364		return(&((buf_block_t*) bpage)->mutex);
365	}
366}
367
368/*********************************************************************//**
369Get the flush type of a page.
370@return	flush type */
371UNIV_INLINE
372buf_flush_t
373buf_page_get_flush_type(
374/*====================*/
375	const buf_page_t*	bpage)	/*!< in: buffer page */
376{
377	buf_flush_t	flush_type = (buf_flush_t) bpage->flush_type;
378
379#ifdef UNIV_DEBUG
380	switch (flush_type) {
381	case BUF_FLUSH_LRU:
382	case BUF_FLUSH_LIST:
383	case BUF_FLUSH_SINGLE_PAGE:
384		return(flush_type);
385	case BUF_FLUSH_N_TYPES:
386		ut_error;
387	}
388	ut_error;
389#endif /* UNIV_DEBUG */
390	return(flush_type);
391}
392/*********************************************************************//**
393Set the flush type of a page. */
394UNIV_INLINE
395void
396buf_page_set_flush_type(
397/*====================*/
398	buf_page_t*	bpage,		/*!< in: buffer page */
399	buf_flush_t	flush_type)	/*!< in: flush type */
400{
401	bpage->flush_type = flush_type;
402	ut_ad(buf_page_get_flush_type(bpage) == flush_type);
403}
404
405/*********************************************************************//**
406Map a block to a file page. */
407UNIV_INLINE
408void
409buf_block_set_file_page(
410/*====================*/
411	buf_block_t*		block,	/*!< in/out: pointer to control block */
412	ulint			space,	/*!< in: tablespace id */
413	ulint			page_no)/*!< in: page number */
414{
415	buf_block_set_state(block, BUF_BLOCK_FILE_PAGE);
416	block->page.space = static_cast<ib_uint32_t>(space);
417	block->page.offset = static_cast<ib_uint32_t>(page_no);
418}
419
420/*********************************************************************//**
421Gets the io_fix state of a block.
422@return	io_fix state */
423UNIV_INLINE
424enum buf_io_fix
425buf_page_get_io_fix(
426/*================*/
427	const buf_page_t*	bpage)	/*!< in: pointer to the control block */
428{
429	ut_ad(bpage != NULL);
430
431	enum buf_io_fix	io_fix = (enum buf_io_fix) bpage->io_fix;
432#ifdef UNIV_DEBUG
433	switch (io_fix) {
434	case BUF_IO_NONE:
435	case BUF_IO_READ:
436	case BUF_IO_WRITE:
437	case BUF_IO_PIN:
438		return(io_fix);
439	}
440	ut_error;
441#endif /* UNIV_DEBUG */
442	return(io_fix);
443}
444
445/*********************************************************************//**
446Gets the io_fix state of a block.
447@return	io_fix state */
448UNIV_INLINE
449enum buf_io_fix
450buf_block_get_io_fix(
451/*=================*/
452	const buf_block_t*	block)	/*!< in: pointer to the control block */
453{
454	return(buf_page_get_io_fix(&block->page));
455}
456
457/*********************************************************************//**
458Sets the io_fix state of a block. */
459UNIV_INLINE
460void
461buf_page_set_io_fix(
462/*================*/
463	buf_page_t*	bpage,	/*!< in/out: control block */
464	enum buf_io_fix	io_fix)	/*!< in: io_fix state */
465{
466#ifdef UNIV_DEBUG
467	buf_pool_t*	buf_pool = buf_pool_from_bpage(bpage);
468	ut_ad(buf_pool_mutex_own(buf_pool));
469#endif
470	ut_ad(mutex_own(buf_page_get_mutex(bpage)));
471
472	bpage->io_fix = io_fix;
473	ut_ad(buf_page_get_io_fix(bpage) == io_fix);
474}
475
476/*********************************************************************//**
477Sets the io_fix state of a block. */
478UNIV_INLINE
479void
480buf_block_set_io_fix(
481/*=================*/
482	buf_block_t*	block,	/*!< in/out: control block */
483	enum buf_io_fix	io_fix)	/*!< in: io_fix state */
484{
485	buf_page_set_io_fix(&block->page, io_fix);
486}
487
488/*********************************************************************//**
489Makes a block sticky. A sticky block implies that even after we release
490the buf_pool->mutex and the block->mutex:
491* it cannot be removed from the flush_list
492* the block descriptor cannot be relocated
493* it cannot be removed from the LRU list
494Note that:
495* the block can still change its position in the LRU list
496* the next and previous pointers can change. */
497UNIV_INLINE
498void
499buf_page_set_sticky(
500/*================*/
501	buf_page_t*	bpage)	/*!< in/out: control block */
502{
503#ifdef UNIV_DEBUG
504	buf_pool_t*	buf_pool = buf_pool_from_bpage(bpage);
505	ut_ad(buf_pool_mutex_own(buf_pool));
506#endif
507	ut_ad(mutex_own(buf_page_get_mutex(bpage)));
508	ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
509
510	bpage->io_fix = BUF_IO_PIN;
511}
512
513/*********************************************************************//**
514Removes stickiness of a block. */
515UNIV_INLINE
516void
517buf_page_unset_sticky(
518/*==================*/
519	buf_page_t*	bpage)	/*!< in/out: control block */
520{
521#ifdef UNIV_DEBUG
522	buf_pool_t*	buf_pool = buf_pool_from_bpage(bpage);
523	ut_ad(buf_pool_mutex_own(buf_pool));
524#endif
525	ut_ad(mutex_own(buf_page_get_mutex(bpage)));
526	ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_PIN);
527
528	bpage->io_fix = BUF_IO_NONE;
529}
530
531/********************************************************************//**
532Determine if a buffer block can be relocated in memory.  The block
533can be dirty, but it must not be I/O-fixed or bufferfixed. */
534UNIV_INLINE
535ibool
536buf_page_can_relocate(
537/*==================*/
538	const buf_page_t*	bpage)	/*!< control block being relocated */
539{
540#ifdef UNIV_DEBUG
541	buf_pool_t*	buf_pool = buf_pool_from_bpage(bpage);
542	ut_ad(buf_pool_mutex_own(buf_pool));
543#endif
544	ut_ad(mutex_own(buf_page_get_mutex(bpage)));
545	ut_ad(buf_page_in_file(bpage));
546	ut_ad(bpage->in_LRU_list);
547
548	return(buf_page_get_io_fix(bpage) == BUF_IO_NONE
549	       && bpage->buf_fix_count == 0);
550}
551
552/*********************************************************************//**
553Determine if a block has been flagged old.
554@return	TRUE if old */
555UNIV_INLINE
556ibool
557buf_page_is_old(
558/*============*/
559	const buf_page_t*	bpage)	/*!< in: control block */
560{
561#ifdef UNIV_DEBUG
562	buf_pool_t*	buf_pool = buf_pool_from_bpage(bpage);
563	ut_ad(buf_pool_mutex_own(buf_pool));
564#endif
565	ut_ad(buf_page_in_file(bpage));
566
567	return(bpage->old);
568}
569
570/*********************************************************************//**
571Flag a block old. */
572UNIV_INLINE
573void
574buf_page_set_old(
575/*=============*/
576	buf_page_t*	bpage,	/*!< in/out: control block */
577	ibool		old)	/*!< in: old */
578{
579#ifdef UNIV_DEBUG
580	buf_pool_t*	buf_pool = buf_pool_from_bpage(bpage);
581#endif /* UNIV_DEBUG */
582	ut_a(buf_page_in_file(bpage));
583	ut_ad(buf_pool_mutex_own(buf_pool));
584	ut_ad(bpage->in_LRU_list);
585
586#ifdef UNIV_LRU_DEBUG
587	ut_a((buf_pool->LRU_old_len == 0) == (buf_pool->LRU_old == NULL));
588	/* If a block is flagged "old", the LRU_old list must exist. */
589	ut_a(!old || buf_pool->LRU_old);
590
591	if (UT_LIST_GET_PREV(LRU, bpage) && UT_LIST_GET_NEXT(LRU, bpage)) {
592		const buf_page_t*	prev = UT_LIST_GET_PREV(LRU, bpage);
593		const buf_page_t*	next = UT_LIST_GET_NEXT(LRU, bpage);
594		if (prev->old == next->old) {
595			ut_a(prev->old == old);
596		} else {
597			ut_a(!prev->old);
598			ut_a(buf_pool->LRU_old == (old ? bpage : next));
599		}
600	}
601#endif /* UNIV_LRU_DEBUG */
602
603	bpage->old = old;
604}
605
606/*********************************************************************//**
607Determine the time of first access of a block in the buffer pool.
608@return	ut_time_ms() at the time of first access, 0 if not accessed */
609UNIV_INLINE
610unsigned
611buf_page_is_accessed(
612/*=================*/
613	const buf_page_t*	bpage)	/*!< in: control block */
614{
615	ut_ad(buf_page_in_file(bpage));
616
617	return(bpage->access_time);
618}
619
620/*********************************************************************//**
621Flag a block accessed. */
622UNIV_INLINE
623void
624buf_page_set_accessed(
625/*==================*/
626	buf_page_t*	bpage)		/*!< in/out: control block */
627{
628#ifdef UNIV_DEBUG
629	buf_pool_t*	buf_pool = buf_pool_from_bpage(bpage);
630	ut_ad(!buf_pool_mutex_own(buf_pool));
631	ut_ad(mutex_own(buf_page_get_mutex(bpage)));
632#endif /* UNIV_DEBUG */
633
634	ut_a(buf_page_in_file(bpage));
635
636	if (bpage->access_time == 0) {
637		/* Make this the time of the first access. */
638		bpage->access_time = static_cast<uint>(ut_time_ms());
639	}
640}
641
642/*********************************************************************//**
643Gets the buf_block_t handle of a buffered file block if an uncompressed
644page frame exists, or NULL.
645@return	control block, or NULL */
646UNIV_INLINE
647buf_block_t*
648buf_page_get_block(
649/*===============*/
650	buf_page_t*	bpage)	/*!< in: control block, or NULL */
651{
652	if (bpage != NULL) {
653		ut_ad(buf_page_in_file(bpage));
654
655		if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE) {
656			return((buf_block_t*) bpage);
657		}
658	}
659
660	return(NULL);
661}
662#endif /* !UNIV_HOTBACKUP */
663
664#ifdef UNIV_DEBUG
665/*********************************************************************//**
666Gets a pointer to the memory frame of a block.
667@return	pointer to the frame */
668UNIV_INLINE
669buf_frame_t*
670buf_block_get_frame(
671/*================*/
672	const buf_block_t*	block)	/*!< in: pointer to the control block */
673{
674	ut_ad(block);
675
676	switch (buf_block_get_state(block)) {
677	case BUF_BLOCK_POOL_WATCH:
678	case BUF_BLOCK_ZIP_PAGE:
679	case BUF_BLOCK_ZIP_DIRTY:
680	case BUF_BLOCK_NOT_USED:
681		ut_error;
682		break;
683	case BUF_BLOCK_FILE_PAGE:
684# ifndef UNIV_HOTBACKUP
685		ut_a(block->page.buf_fix_count > 0);
686# endif /* !UNIV_HOTBACKUP */
687		/* fall through */
688	case BUF_BLOCK_READY_FOR_USE:
689	case BUF_BLOCK_MEMORY:
690	case BUF_BLOCK_REMOVE_HASH:
691		goto ok;
692	}
693	ut_error;
694ok:
695	return((buf_frame_t*) block->frame);
696}
697#endif /* UNIV_DEBUG */
698
699/*********************************************************************//**
700Gets the space id of a block.
701@return	space id */
702UNIV_INLINE
703ulint
704buf_page_get_space(
705/*===============*/
706	const buf_page_t*	bpage)	/*!< in: pointer to the control block */
707{
708	ut_ad(bpage);
709	ut_a(buf_page_in_file(bpage));
710
711	return(bpage->space);
712}
713
714/*********************************************************************//**
715Gets the space id of a block.
716@return	space id */
717UNIV_INLINE
718ulint
719buf_block_get_space(
720/*================*/
721	const buf_block_t*	block)	/*!< in: pointer to the control block */
722{
723	ut_ad(block);
724	ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
725
726	return(block->page.space);
727}
728
729/*********************************************************************//**
730Gets the page number of a block.
731@return	page number */
732UNIV_INLINE
733ulint
734buf_page_get_page_no(
735/*=================*/
736	const buf_page_t*	bpage)	/*!< in: pointer to the control block */
737{
738	ut_ad(bpage);
739	ut_a(buf_page_in_file(bpage));
740
741	return(bpage->offset);
742}
743/***********************************************************************
744FIXME_FTS Gets the frame the pointer is pointing to. */
745UNIV_INLINE
746buf_frame_t*
747buf_frame_align(
748/*============*/
749                        /* out: pointer to frame */
750        byte*   ptr)    /* in: pointer to a frame */
751{
752        buf_frame_t*    frame;
753
754        ut_ad(ptr);
755
756        frame = (buf_frame_t*) ut_align_down(ptr, UNIV_PAGE_SIZE);
757
758        return(frame);
759}
760
761/*********************************************************************//**
762Gets the page number of a block.
763@return	page number */
764UNIV_INLINE
765ulint
766buf_block_get_page_no(
767/*==================*/
768	const buf_block_t*	block)	/*!< in: pointer to the control block */
769{
770	ut_ad(block);
771	ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
772
773	return(block->page.offset);
774}
775
776/*********************************************************************//**
777Gets the compressed page size of a block.
778@return	compressed page size, or 0 */
779UNIV_INLINE
780ulint
781buf_page_get_zip_size(
782/*==================*/
783	const buf_page_t*	bpage)	/*!< in: pointer to the control block */
784{
785	return(bpage->zip.ssize
786	       ? (UNIV_ZIP_SIZE_MIN >> 1) << bpage->zip.ssize : 0);
787}
788
789/*********************************************************************//**
790Gets the compressed page size of a block.
791@return	compressed page size, or 0 */
792UNIV_INLINE
793ulint
794buf_block_get_zip_size(
795/*===================*/
796	const buf_block_t*	block)	/*!< in: pointer to the control block */
797{
798	return(block->page.zip.ssize
799	       ? (UNIV_ZIP_SIZE_MIN >> 1) << block->page.zip.ssize : 0);
800}
801
802#ifndef UNIV_HOTBACKUP
803#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
804/*********************************************************************//**
805Gets the compressed page descriptor corresponding to an uncompressed page
806if applicable.
807@return	compressed page descriptor, or NULL */
808UNIV_INLINE
809const page_zip_des_t*
810buf_frame_get_page_zip(
811/*===================*/
812	const byte*	ptr)	/*!< in: pointer to the page */
813{
814	return(buf_block_get_page_zip(buf_block_align(ptr)));
815}
816#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
817#endif /* !UNIV_HOTBACKUP */
818
819/**********************************************************************//**
820Gets the space id, page offset, and byte offset within page of a
821pointer pointing to a buffer frame containing a file page. */
822UNIV_INLINE
823void
824buf_ptr_get_fsp_addr(
825/*=================*/
826	const void*	ptr,	/*!< in: pointer to a buffer frame */
827	ulint*		space,	/*!< out: space id */
828	fil_addr_t*	addr)	/*!< out: page offset and byte offset */
829{
830	const page_t*	page = (const page_t*) ut_align_down(ptr,
831							     UNIV_PAGE_SIZE);
832
833	*space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
834	addr->page = mach_read_from_4(page + FIL_PAGE_OFFSET);
835	addr->boffset = ut_align_offset(ptr, UNIV_PAGE_SIZE);
836}
837
838#ifndef UNIV_HOTBACKUP
839/**********************************************************************//**
840Gets the hash value of the page the pointer is pointing to. This can be used
841in searches in the lock hash table.
842@return	lock hash value */
843UNIV_INLINE
844ulint
845buf_block_get_lock_hash_val(
846/*========================*/
847	const buf_block_t*	block)	/*!< in: block */
848{
849	ut_ad(block);
850	ut_ad(buf_page_in_file(&block->page));
851#ifdef UNIV_SYNC_DEBUG
852	ut_ad(rw_lock_own(&(((buf_block_t*) block)->lock), RW_LOCK_EXCLUSIVE)
853	      || rw_lock_own(&(((buf_block_t*) block)->lock), RW_LOCK_SHARED));
854#endif /* UNIV_SYNC_DEBUG */
855	return(block->lock_hash_val);
856}
857
858/********************************************************************//**
859Allocates a buf_page_t descriptor. This function must succeed. In case
860of failure we assert in this function.
861@return: the allocated descriptor. */
862UNIV_INLINE
863buf_page_t*
864buf_page_alloc_descriptor(void)
865/*===========================*/
866{
867	buf_page_t*	bpage;
868
869	bpage = (buf_page_t*) ut_malloc(sizeof *bpage);
870	ut_d(memset(bpage, 0, sizeof *bpage));
871	UNIV_MEM_ALLOC(bpage, sizeof *bpage);
872
873	return(bpage);
874}
875
876/********************************************************************//**
877Free a buf_page_t descriptor. */
878UNIV_INLINE
879void
880buf_page_free_descriptor(
881/*=====================*/
882	buf_page_t*	bpage)	/*!< in: bpage descriptor to free. */
883{
884	ut_free(bpage);
885}
886
887/********************************************************************//**
888Frees a buffer block which does not contain a file page. */
889UNIV_INLINE
890void
891buf_block_free(
892/*===========*/
893	buf_block_t*	block)	/*!< in, own: block to be freed */
894{
895	buf_pool_t*	buf_pool = buf_pool_from_bpage((buf_page_t*) block);
896
897	buf_pool_mutex_enter(buf_pool);
898
899	mutex_enter(&block->mutex);
900
901	ut_a(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE);
902
903	buf_LRU_block_free_non_file_page(block);
904
905	mutex_exit(&block->mutex);
906
907	buf_pool_mutex_exit(buf_pool);
908}
909#endif /* !UNIV_HOTBACKUP */
910
911/*********************************************************************//**
912Copies contents of a buffer frame to a given buffer.
913@return	buf */
914UNIV_INLINE
915byte*
916buf_frame_copy(
917/*===========*/
918	byte*			buf,	/*!< in: buffer to copy to */
919	const buf_frame_t*	frame)	/*!< in: buffer frame */
920{
921	ut_ad(buf && frame);
922
923	ut_memcpy(buf, frame, UNIV_PAGE_SIZE);
924
925	return(buf);
926}
927
928#ifndef UNIV_HOTBACKUP
929/********************************************************************//**
930Calculates a folded value of a file page address to use in the page hash
931table.
932@return	the folded value */
933UNIV_INLINE
934ulint
935buf_page_address_fold(
936/*==================*/
937	ulint	space,	/*!< in: space id */
938	ulint	offset)	/*!< in: offset of the page within space */
939{
940	return((space << 20) + space + offset);
941}
942
943/********************************************************************//**
944Gets the youngest modification log sequence number for a frame.
945Returns zero if not file page or no modification occurred yet.
946@return	newest modification to page */
947UNIV_INLINE
948lsn_t
949buf_page_get_newest_modification(
950/*=============================*/
951	const buf_page_t*	bpage)	/*!< in: block containing the
952					page frame */
953{
954	lsn_t		lsn;
955	ib_mutex_t*	block_mutex = buf_page_get_mutex(bpage);
956
957	mutex_enter(block_mutex);
958
959	if (buf_page_in_file(bpage)) {
960		lsn = bpage->newest_modification;
961	} else {
962		lsn = 0;
963	}
964
965	mutex_exit(block_mutex);
966
967	return(lsn);
968}
969
970/********************************************************************//**
971Increments the modify clock of a frame by 1. The caller must (1) own the
972buf_pool mutex and block bufferfix count has to be zero, (2) or own an x-lock
973on the block. */
974UNIV_INLINE
975void
976buf_block_modify_clock_inc(
977/*=======================*/
978	buf_block_t*	block)	/*!< in: block */
979{
980#ifdef UNIV_SYNC_DEBUG
981	buf_pool_t*	buf_pool = buf_pool_from_bpage((buf_page_t*) block);
982
983	ut_ad((buf_pool_mutex_own(buf_pool)
984	       && (block->page.buf_fix_count == 0))
985	      || rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
986#endif /* UNIV_SYNC_DEBUG */
987
988	block->modify_clock++;
989}
990
991/********************************************************************//**
992Returns the value of the modify clock. The caller must have an s-lock
993or x-lock on the block.
994@return	value */
995UNIV_INLINE
996ib_uint64_t
997buf_block_get_modify_clock(
998/*=======================*/
999	buf_block_t*	block)	/*!< in: block */
1000{
1001#ifdef UNIV_SYNC_DEBUG
1002	ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
1003	      || rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
1004#endif /* UNIV_SYNC_DEBUG */
1005
1006	return(block->modify_clock);
1007}
1008
1009/*******************************************************************//**
1010Increments the bufferfix count. */
1011UNIV_INLINE
1012void
1013buf_block_fix(
1014/*===========*/
1015	buf_block_t*	block)	/*!< in/out: block to bufferfix */
1016{
1017#ifdef PAGE_ATOMIC_REF_COUNT
1018	os_atomic_increment_uint32(&block->page.buf_fix_count, 1);
1019#else
1020	ib_mutex_t*	block_mutex = buf_page_get_mutex(&block->page);
1021
1022	mutex_enter(block_mutex);
1023	++block->page.buf_fix_count;
1024	mutex_exit(block_mutex);
1025#endif /* PAGE_ATOMIC_REF_COUNT */
1026}
1027
1028/*******************************************************************//**
1029Increments the bufferfix count. */
1030UNIV_INLINE
1031void
1032buf_block_buf_fix_inc_func(
1033/*=======================*/
1034#ifdef UNIV_SYNC_DEBUG
1035	const char*	file,	/*!< in: file name */
1036	ulint		line,	/*!< in: line */
1037#endif /* UNIV_SYNC_DEBUG */
1038	buf_block_t*	block)	/*!< in/out: block to bufferfix */
1039{
1040#ifdef UNIV_SYNC_DEBUG
1041	ibool	ret;
1042
1043	ret = rw_lock_s_lock_nowait(&(block->debug_latch), file, line);
1044	ut_a(ret);
1045#endif /* UNIV_SYNC_DEBUG */
1046
1047#ifdef PAGE_ATOMIC_REF_COUNT
1048	os_atomic_increment_uint32(&block->page.buf_fix_count, 1);
1049#else
1050	ut_ad(mutex_own(&block->mutex));
1051
1052	++block->page.buf_fix_count;
1053#endif /* PAGE_ATOMIC_REF_COUNT */
1054}
1055
1056/*******************************************************************//**
1057Decrements the bufferfix count. */
1058UNIV_INLINE
1059void
1060buf_block_unfix(
1061/*============*/
1062	buf_block_t*	block)	/*!< in/out: block to bufferunfix */
1063{
1064	ut_ad(block->page.buf_fix_count > 0);
1065
1066#ifdef PAGE_ATOMIC_REF_COUNT
1067	os_atomic_decrement_uint32(&block->page.buf_fix_count, 1);
1068#else
1069	ib_mutex_t*	block_mutex = buf_page_get_mutex(&block->page);
1070
1071	mutex_enter(block_mutex);
1072	--block->page.buf_fix_count;
1073	mutex_exit(block_mutex);
1074#endif /* PAGE_ATOMIC_REF_COUNT */
1075}
1076
1077/*******************************************************************//**
1078Decrements the bufferfix count. */
1079UNIV_INLINE
1080void
1081buf_block_buf_fix_dec(
1082/*==================*/
1083	buf_block_t*	block)	/*!< in/out: block to bufferunfix */
1084{
1085	ut_ad(block->page.buf_fix_count > 0);
1086
1087#ifdef PAGE_ATOMIC_REF_COUNT
1088	os_atomic_decrement_uint32(&block->page.buf_fix_count, 1);
1089#else
1090	mutex_enter(&block->mutex);
1091	--block->page.buf_fix_count;
1092	mutex_exit(&block->mutex);
1093#endif /* PAGE_ATOMIC_REF_COUNT */
1094
1095#ifdef UNIV_SYNC_DEBUG
1096	rw_lock_s_unlock(&block->debug_latch);
1097#endif
1098}
1099
1100/******************************************************************//**
1101Returns the buffer pool instance given space and offset of page
1102@return buffer pool */
1103UNIV_INLINE
1104buf_pool_t*
1105buf_pool_get(
1106/*==========*/
1107	ulint	space,	/*!< in: space id */
1108	ulint	offset)	/*!< in: offset of the page within space */
1109{
1110	ulint	fold;
1111	ulint	index;
1112	ulint	ignored_offset;
1113
1114	ignored_offset = offset >> 6; /* 2log of BUF_READ_AHEAD_AREA (64)*/
1115	fold = buf_page_address_fold(space, ignored_offset);
1116	index = fold % srv_buf_pool_instances;
1117	return(&buf_pool_ptr[index]);
1118}
1119
1120/******************************************************************//**
1121Returns the buffer pool instance given its array index
1122@return buffer pool */
1123UNIV_INLINE
1124buf_pool_t*
1125buf_pool_from_array(
1126/*================*/
1127	ulint	index)		/*!< in: array index to get
1128				buffer pool instance from */
1129{
1130	ut_ad(index < MAX_BUFFER_POOLS);
1131	ut_ad(index < srv_buf_pool_instances);
1132	return(&buf_pool_ptr[index]);
1133}
1134
1135/******************************************************************//**
1136Returns the control block of a file page, NULL if not found.
1137@return	block, NULL if not found */
1138UNIV_INLINE
1139buf_page_t*
1140buf_page_hash_get_low(
1141/*==================*/
1142	buf_pool_t*	buf_pool,/*!< buffer pool instance */
1143	ulint		space,	/*!< in: space id */
1144	ulint		offset,	/*!< in: offset of the page within space */
1145	ulint		fold)	/*!< in: buf_page_address_fold(space, offset) */
1146{
1147	buf_page_t*	bpage;
1148
1149#ifdef UNIV_SYNC_DEBUG
1150	ulint		hash_fold;
1151	rw_lock_t*	hash_lock;
1152
1153	hash_fold = buf_page_address_fold(space, offset);
1154	ut_ad(hash_fold == fold);
1155
1156	hash_lock = hash_get_lock(buf_pool->page_hash, fold);
1157	ut_ad(rw_lock_own(hash_lock, RW_LOCK_EX)
1158	      || rw_lock_own(hash_lock, RW_LOCK_SHARED));
1159#endif /* UNIV_SYNC_DEBUG */
1160
1161	/* Look for the page in the hash table */
1162
1163	HASH_SEARCH(hash, buf_pool->page_hash, fold, buf_page_t*, bpage,
1164		    ut_ad(bpage->in_page_hash && !bpage->in_zip_hash
1165			  && buf_page_in_file(bpage)),
1166		    bpage->space == space && bpage->offset == offset);
1167	if (bpage) {
1168		ut_a(buf_page_in_file(bpage));
1169		ut_ad(bpage->in_page_hash);
1170		ut_ad(!bpage->in_zip_hash);
1171	}
1172
1173	return(bpage);
1174}
1175
1176/******************************************************************//**
1177Returns the control block of a file page, NULL if not found.
1178If the block is found and lock is not NULL then the appropriate
1179page_hash lock is acquired in the specified lock mode. Otherwise,
1180mode value is ignored. It is up to the caller to release the
1181lock. If the block is found and the lock is NULL then the page_hash
1182lock is released by this function.
1183@return	block, NULL if not found, or watch sentinel (if watch is true) */
1184UNIV_INLINE
1185buf_page_t*
1186buf_page_hash_get_locked(
1187/*=====================*/
1188					/*!< out: pointer to the bpage,
1189					or NULL; if NULL, hash_lock
1190					is also NULL. */
1191	buf_pool_t*	buf_pool,	/*!< buffer pool instance */
1192	ulint		space,		/*!< in: space id */
1193	ulint		offset,		/*!< in: page number */
1194	rw_lock_t**	lock,		/*!< in/out: lock of the page
1195					hash acquired if bpage is
1196					found. NULL otherwise. If NULL
1197					is passed then the hash_lock
1198					is released by this function */
1199	ulint		lock_mode,	/*!< in: RW_LOCK_EX or
1200					RW_LOCK_SHARED. Ignored if
1201					lock == NULL */
1202	bool		watch)		/*!< in: if true, return watch
1203					sentinel also. */
1204{
1205	buf_page_t*	bpage = NULL;
1206	ulint		fold;
1207	rw_lock_t*	hash_lock;
1208	ulint		mode = RW_LOCK_SHARED;
1209
1210	if (lock != NULL) {
1211		*lock = NULL;
1212		ut_ad(lock_mode == RW_LOCK_EX
1213		      || lock_mode == RW_LOCK_SHARED);
1214		mode = lock_mode;
1215	}
1216
1217	fold = buf_page_address_fold(space, offset);
1218	hash_lock = hash_get_lock(buf_pool->page_hash, fold);
1219
1220#ifdef UNIV_SYNC_DEBUG
1221	ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX)
1222	      && !rw_lock_own(hash_lock, RW_LOCK_SHARED));
1223#endif /* UNIV_SYNC_DEBUG */
1224
1225	if (mode == RW_LOCK_SHARED) {
1226		rw_lock_s_lock(hash_lock);
1227	} else {
1228		rw_lock_x_lock(hash_lock);
1229	}
1230
1231	bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
1232
1233	if (!bpage || buf_pool_watch_is_sentinel(buf_pool, bpage)) {
1234		if (!watch) {
1235			bpage = NULL;
1236		}
1237		goto unlock_and_exit;
1238	}
1239
1240	ut_ad(buf_page_in_file(bpage));
1241	ut_ad(offset == bpage->offset);
1242	ut_ad(space == bpage->space);
1243
1244	if (lock == NULL) {
1245		/* The caller wants us to release the page_hash lock */
1246		goto unlock_and_exit;
1247	} else {
1248		/* To be released by the caller */
1249		*lock = hash_lock;
1250		goto exit;
1251	}
1252
1253unlock_and_exit:
1254	if (mode == RW_LOCK_SHARED) {
1255		rw_lock_s_unlock(hash_lock);
1256	} else {
1257		rw_lock_x_unlock(hash_lock);
1258	}
1259exit:
1260	return(bpage);
1261}
1262
1263/******************************************************************//**
1264Returns the control block of a file page, NULL if not found.
1265If the block is found and lock is not NULL then the appropriate
1266page_hash lock is acquired in the specified lock mode. Otherwise,
1267mode value is ignored. It is up to the caller to release the
1268lock. If the block is found and the lock is NULL then the page_hash
1269lock is released by this function.
1270@return	block, NULL if not found */
1271UNIV_INLINE
1272buf_block_t*
1273buf_block_hash_get_locked(
1274/*=====================*/
1275					/*!< out: pointer to the bpage,
1276					or NULL; if NULL, hash_lock
1277					is also NULL. */
1278	buf_pool_t*	buf_pool,	/*!< buffer pool instance */
1279	ulint		space,		/*!< in: space id */
1280	ulint		offset,		/*!< in: page number */
1281	rw_lock_t**	lock,		/*!< in/out: lock of the page
1282					hash acquired if bpage is
1283					found. NULL otherwise. If NULL
1284					is passed then the hash_lock
1285					is released by this function */
1286	ulint		lock_mode)	/*!< in: RW_LOCK_EX or
1287					RW_LOCK_SHARED. Ignored if
1288					lock == NULL */
1289{
1290	buf_page_t*	bpage = buf_page_hash_get_locked(buf_pool,
1291							 space,
1292							 offset,
1293							 lock,
1294							 lock_mode);
1295	buf_block_t*	block = buf_page_get_block(bpage);
1296
1297	if (block) {
1298		ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
1299#ifdef UNIV_SYNC_DEBUG
1300		ut_ad(!lock || rw_lock_own(*lock, lock_mode));
1301#endif /* UNIV_SYNC_DEBUG */
1302		return(block);
1303	} else if (bpage) {
1304		/* It is not a block. Just a bpage */
1305		ut_ad(buf_page_in_file(bpage));
1306
1307		if (lock) {
1308			if (lock_mode == RW_LOCK_SHARED) {
1309				rw_lock_s_unlock(*lock);
1310			} else {
1311				rw_lock_x_unlock(*lock);
1312			}
1313		}
1314		*lock = NULL;
1315		return(NULL);
1316	}
1317
1318	ut_ad(!bpage);
1319	ut_ad(lock == NULL ||*lock == NULL);
1320	return(NULL);
1321}
1322
1323/********************************************************************//**
1324Returns TRUE if the page can be found in the buffer pool hash table.
1325
1326NOTE that it is possible that the page is not yet read from disk,
1327though.
1328
1329@return	TRUE if found in the page hash table */
1330UNIV_INLINE
1331ibool
1332buf_page_peek(
1333/*==========*/
1334	ulint	space,	/*!< in: space id */
1335	ulint	offset)	/*!< in: page number */
1336{
1337	buf_pool_t*		buf_pool = buf_pool_get(space, offset);
1338
1339	return(buf_page_hash_get(buf_pool, space, offset) != NULL);
1340}
1341
1342/********************************************************************//**
1343Releases a compressed-only page acquired with buf_page_get_zip(). */
1344UNIV_INLINE
1345void
1346buf_page_release_zip(
1347/*=================*/
1348	buf_page_t*	bpage)		/*!< in: buffer block */
1349{
1350	buf_block_t*	block;
1351
1352	block = (buf_block_t*) bpage;
1353
1354	switch (buf_page_get_state(bpage)) {
1355	case BUF_BLOCK_FILE_PAGE:
1356#ifdef UNIV_SYNC_DEBUG
1357		rw_lock_s_unlock(&block->debug_latch);
1358#endif /* UNUV_SYNC_DEBUG */
1359		/* Fall through */
1360	case BUF_BLOCK_ZIP_PAGE:
1361	case BUF_BLOCK_ZIP_DIRTY:
1362		buf_block_unfix(block);
1363		return;
1364
1365	case BUF_BLOCK_POOL_WATCH:
1366	case BUF_BLOCK_NOT_USED:
1367	case BUF_BLOCK_READY_FOR_USE:
1368	case BUF_BLOCK_MEMORY:
1369	case BUF_BLOCK_REMOVE_HASH:
1370		break;
1371	}
1372
1373	ut_error;
1374}
1375
1376/********************************************************************//**
1377Decrements the bufferfix count of a buffer control block and releases
1378a latch, if specified. */
1379UNIV_INLINE
1380void
1381buf_page_release(
1382/*=============*/
1383	buf_block_t*	block,		/*!< in: buffer block */
1384	ulint		rw_latch)	/*!< in: RW_S_LATCH, RW_X_LATCH,
1385					RW_NO_LATCH */
1386{
1387	ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
1388
1389#ifdef UNIV_SYNC_DEBUG
1390	rw_lock_s_unlock(&(block->debug_latch));
1391#endif
1392	if (rw_latch == RW_S_LATCH) {
1393		rw_lock_s_unlock(&(block->lock));
1394	} else if (rw_latch == RW_X_LATCH) {
1395		rw_lock_x_unlock(&(block->lock));
1396	}
1397
1398	buf_block_unfix(block);
1399}
1400
1401#ifdef UNIV_SYNC_DEBUG
1402/*********************************************************************//**
1403Adds latch level info for the rw-lock protecting the buffer frame. This
1404should be called in the debug version after a successful latching of a
1405page if we know the latching order level of the acquired latch. */
1406UNIV_INLINE
1407void
1408buf_block_dbg_add_level(
1409/*====================*/
1410	buf_block_t*	block,	/*!< in: buffer page
1411				where we have acquired latch */
1412	ulint		level)	/*!< in: latching order level */
1413{
1414	sync_thread_add_level(&block->lock, level, FALSE);
1415}
1416
1417#endif /* UNIV_SYNC_DEBUG */
1418/********************************************************************//**
1419Acquire mutex on all buffer pool instances. */
1420UNIV_INLINE
1421void
1422buf_pool_mutex_enter_all(void)
1423/*==========================*/
1424{
1425	ulint   i;
1426
1427	for (i = 0; i < srv_buf_pool_instances; i++) {
1428		buf_pool_t*	buf_pool;
1429
1430		buf_pool = buf_pool_from_array(i);
1431		buf_pool_mutex_enter(buf_pool);
1432	}
1433}
1434
1435/********************************************************************//**
1436Release mutex on all buffer pool instances. */
1437UNIV_INLINE
1438void
1439buf_pool_mutex_exit_all(void)
1440/*=========================*/
1441{
1442	ulint   i;
1443
1444	for (i = 0; i < srv_buf_pool_instances; i++) {
1445		buf_pool_t*	buf_pool;
1446
1447		buf_pool = buf_pool_from_array(i);
1448		buf_pool_mutex_exit(buf_pool);
1449	}
1450}
1451/*********************************************************************//**
1452Get the nth chunk's buffer block in the specified buffer pool.
1453@return the nth chunk's buffer block. */
1454UNIV_INLINE
1455buf_block_t*
1456buf_get_nth_chunk_block(
1457/*====================*/
1458	const buf_pool_t* buf_pool,	/*!< in: buffer pool instance */
1459	ulint		n,		/*!< in: nth chunk in the buffer pool */
1460	ulint*		chunk_size)	/*!< in: chunk size */
1461{
1462	const buf_chunk_t*	chunk;
1463
1464	chunk = buf_pool->chunks + n;
1465	*chunk_size = chunk->size;
1466	return(chunk->blocks);
1467}
1468#endif /* !UNIV_HOTBACKUP */
1469