/****************************************************** The database buffer buf_pool (c) 1995 Innobase Oy Created 11/5/1995 Heikki Tuuri *******************************************************/ #include "buf0flu.h" #include "buf0lru.h" #include "buf0rea.h" #include "mtr0mtr.h" /************************************************************************ Reads the freed_page_clock of a buffer block. */ UNIV_INLINE ulint buf_page_get_freed_page_clock( /*==========================*/ /* out: freed_page_clock */ const buf_page_t* bpage) /* in: block */ { return(bpage->freed_page_clock); } /************************************************************************ Reads the freed_page_clock of a buffer block. */ UNIV_INLINE ulint buf_block_get_freed_page_clock( /*===========================*/ /* out: freed_page_clock */ const buf_block_t* block) /* in: block */ { return(buf_page_get_freed_page_clock(&block->page)); } /************************************************************************ Recommends a move of a block to the start of the LRU list if there is danger of dropping from the buffer pool. NOTE: does not reserve the buffer pool mutex. */ UNIV_INLINE ibool buf_page_peek_if_too_old( /*=====================*/ /* out: TRUE if should be made younger */ const buf_page_t* bpage) /* in: block to make younger */ { return(buf_pool->freed_page_clock >= buf_page_get_freed_page_clock(bpage) + 1 + (buf_pool->curr_size / 4)); } /************************************************************************* Gets the current size of buffer buf_pool in bytes. */ UNIV_INLINE ulint buf_pool_get_curr_size(void) /*========================*/ /* out: size in bytes */ { return(buf_pool->curr_size * UNIV_PAGE_SIZE); } /************************************************************************ Gets the smallest oldest_modification lsn for any page in the pool. Returns zero if all modified pages have been flushed to disk. */ UNIV_INLINE ib_uint64_t buf_pool_get_oldest_modification(void) /*==================================*/ /* out: oldest modification in pool, zero if none */ { buf_page_t* bpage; ib_uint64_t lsn; buf_pool_mutex_enter(); bpage = UT_LIST_GET_LAST(buf_pool->flush_list); if (bpage == NULL) { lsn = 0; } else { ut_ad(bpage->in_flush_list); lsn = bpage->oldest_modification; } buf_pool_mutex_exit(); return(lsn); } /*********************************************************************** Increments the buf_pool clock by one and returns its new value. Remember that in the 32 bit version the clock wraps around at 4 billion! */ UNIV_INLINE ulint buf_pool_clock_tic(void) /*====================*/ /* out: new clock value */ { ut_ad(buf_pool_mutex_own()); buf_pool->ulint_clock++; return(buf_pool->ulint_clock); } /************************************************************************* Gets the state of a block. */ UNIV_INLINE enum buf_page_state buf_page_get_state( /*===============*/ /* out: state */ const buf_page_t* bpage) /* in: pointer to the control block */ { enum buf_page_state state = (enum buf_page_state) bpage->state; #ifdef UNIV_DEBUG switch (state) { case BUF_BLOCK_ZIP_FREE: case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_DIRTY: case BUF_BLOCK_NOT_USED: case BUF_BLOCK_READY_FOR_USE: case BUF_BLOCK_FILE_PAGE: case BUF_BLOCK_MEMORY: case BUF_BLOCK_REMOVE_HASH: break; default: ut_error; } #endif /* UNIV_DEBUG */ return(state); } /************************************************************************* Gets the state of a block. */ UNIV_INLINE enum buf_page_state buf_block_get_state( /*================*/ /* out: state */ const buf_block_t* block) /* in: pointer to the control block */ { return(buf_page_get_state(&block->page)); } /************************************************************************* Sets the state of a block. */ UNIV_INLINE void buf_page_set_state( /*===============*/ buf_page_t* bpage, /* in/out: pointer to control block */ enum buf_page_state state) /* in: state */ { #ifdef UNIV_DEBUG enum buf_page_state old_state = buf_page_get_state(bpage); switch (old_state) { case BUF_BLOCK_ZIP_FREE: ut_error; break; case BUF_BLOCK_ZIP_PAGE: ut_a(state == BUF_BLOCK_ZIP_DIRTY); break; case BUF_BLOCK_ZIP_DIRTY: ut_a(state == BUF_BLOCK_ZIP_PAGE); break; case BUF_BLOCK_NOT_USED: ut_a(state == BUF_BLOCK_READY_FOR_USE); break; case BUF_BLOCK_READY_FOR_USE: ut_a(state == BUF_BLOCK_MEMORY || state == BUF_BLOCK_FILE_PAGE || state == BUF_BLOCK_NOT_USED); break; case BUF_BLOCK_MEMORY: ut_a(state == BUF_BLOCK_NOT_USED); break; case BUF_BLOCK_FILE_PAGE: ut_a(state == BUF_BLOCK_NOT_USED || state == BUF_BLOCK_REMOVE_HASH); break; case BUF_BLOCK_REMOVE_HASH: ut_a(state == BUF_BLOCK_MEMORY); break; } #endif /* UNIV_DEBUG */ bpage->state = state; ut_ad(buf_page_get_state(bpage) == state); } /************************************************************************* Sets the state of a block. */ UNIV_INLINE void buf_block_set_state( /*================*/ buf_block_t* block, /* in/out: pointer to control block */ enum buf_page_state state) /* in: state */ { buf_page_set_state(&block->page, state); } /************************************************************************* Determines if a block is mapped to a tablespace. */ UNIV_INLINE ibool buf_page_in_file( /*=============*/ /* out: TRUE if mapped */ const buf_page_t* bpage) /* in: pointer to control block */ { switch (buf_page_get_state(bpage)) { case BUF_BLOCK_ZIP_FREE: /* This is a free page in buf_pool->zip_free[]. Such pages should only be accessed by the buddy allocator. */ ut_error; break; case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_DIRTY: case BUF_BLOCK_FILE_PAGE: return(TRUE); case BUF_BLOCK_NOT_USED: case BUF_BLOCK_READY_FOR_USE: case BUF_BLOCK_MEMORY: case BUF_BLOCK_REMOVE_HASH: break; } return(FALSE); } /************************************************************************* Determines if a block should be on unzip_LRU list. */ UNIV_INLINE ibool buf_page_belongs_to_unzip_LRU( /*==========================*/ /* out: TRUE if block belongs to unzip_LRU */ const buf_page_t* bpage) /* in: pointer to control block */ { ut_ad(buf_page_in_file(bpage)); return(bpage->zip.data && buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); } /************************************************************************* Determine the approximate LRU list position of a block. */ UNIV_INLINE ulint buf_page_get_LRU_position( /*======================*/ /* out: LRU list position */ const buf_page_t* bpage) /* in: control block */ { ut_ad(buf_page_in_file(bpage)); return(bpage->LRU_position); } /************************************************************************* Gets the mutex of a block. */ UNIV_INLINE mutex_t* buf_page_get_mutex( /*===============*/ /* out: pointer to mutex protecting bpage */ const buf_page_t* bpage) /* in: pointer to control block */ { switch (buf_page_get_state(bpage)) { case BUF_BLOCK_ZIP_FREE: ut_error; return(NULL); case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_DIRTY: return(&buf_pool_zip_mutex); default: return(&((buf_block_t*) bpage)->mutex); } } /************************************************************************* Get the flush type of a page. */ UNIV_INLINE enum buf_flush buf_page_get_flush_type( /*====================*/ /* out: flush type */ const buf_page_t* bpage) /* in: buffer page */ { enum buf_flush flush_type = (enum buf_flush) bpage->flush_type; #ifdef UNIV_DEBUG switch (flush_type) { case BUF_FLUSH_LRU: case BUF_FLUSH_SINGLE_PAGE: case BUF_FLUSH_LIST: return(flush_type); case BUF_FLUSH_N_TYPES: break; } ut_error; #endif /* UNIV_DEBUG */ return(flush_type); } /************************************************************************* Set the flush type of a page. */ UNIV_INLINE void buf_page_set_flush_type( /*====================*/ buf_page_t* bpage, /* in: buffer page */ enum buf_flush flush_type) /* in: flush type */ { bpage->flush_type = flush_type; ut_ad(buf_page_get_flush_type(bpage) == flush_type); } /************************************************************************* Map a block to a file page. */ UNIV_INLINE void buf_block_set_file_page( /*====================*/ buf_block_t* block, /* in/out: pointer to control block */ ulint space, /* in: tablespace id */ ulint page_no)/* in: page number */ { buf_block_set_state(block, BUF_BLOCK_FILE_PAGE); block->page.space = space; block->page.offset = page_no; } /************************************************************************* Gets the io_fix state of a block. */ UNIV_INLINE enum buf_io_fix buf_page_get_io_fix( /*================*/ /* out: io_fix state */ const buf_page_t* bpage) /* in: pointer to the control block */ { enum buf_io_fix io_fix = (enum buf_io_fix) bpage->io_fix; #ifdef UNIV_DEBUG switch (io_fix) { case BUF_IO_NONE: case BUF_IO_READ: case BUF_IO_WRITE: return(io_fix); } ut_error; #endif /* UNIV_DEBUG */ return(io_fix); } /************************************************************************* Gets the io_fix state of a block. */ UNIV_INLINE enum buf_io_fix buf_block_get_io_fix( /*================*/ /* out: io_fix state */ const buf_block_t* block) /* in: pointer to the control block */ { return(buf_page_get_io_fix(&block->page)); } /************************************************************************* Sets the io_fix state of a block. */ UNIV_INLINE void buf_page_set_io_fix( /*================*/ buf_page_t* bpage, /* in/out: control block */ enum buf_io_fix io_fix) /* in: io_fix state */ { ut_ad(buf_pool_mutex_own()); ut_ad(mutex_own(buf_page_get_mutex(bpage))); bpage->io_fix = io_fix; ut_ad(buf_page_get_io_fix(bpage) == io_fix); } /************************************************************************* Sets the io_fix state of a block. */ UNIV_INLINE void buf_block_set_io_fix( /*=================*/ buf_block_t* block, /* in/out: control block */ enum buf_io_fix io_fix) /* in: io_fix state */ { buf_page_set_io_fix(&block->page, io_fix); } /************************************************************************ Determine if a buffer block can be relocated in memory. The block can be dirty, but it must not be I/O-fixed or bufferfixed. */ UNIV_INLINE ibool buf_page_can_relocate( /*==================*/ const buf_page_t* bpage) /* control block being relocated */ { ut_ad(buf_pool_mutex_own()); ut_ad(mutex_own(buf_page_get_mutex(bpage))); ut_ad(buf_page_in_file(bpage)); ut_ad(bpage->in_LRU_list); return(buf_page_get_io_fix(bpage) == BUF_IO_NONE && bpage->buf_fix_count == 0); } /************************************************************************* Determine if a block has been flagged old. */ UNIV_INLINE ibool buf_page_is_old( /*============*/ /* out: TRUE if old */ const buf_page_t* bpage) /* in: control block */ { ut_ad(buf_page_in_file(bpage)); return(bpage->old); } /************************************************************************* Flag a block old. */ UNIV_INLINE void buf_page_set_old( /*=============*/ buf_page_t* bpage, /* in/out: control block */ ibool old) /* in: old */ { ut_a(buf_page_in_file(bpage)); ut_ad(buf_pool_mutex_own()); ut_ad(bpage->in_LRU_list); #ifdef UNIV_LRU_DEBUG if (UT_LIST_GET_PREV(LRU, bpage) && UT_LIST_GET_NEXT(LRU, bpage) && UT_LIST_GET_PREV(LRU, bpage)->old == UT_LIST_GET_NEXT(LRU, bpage)->old) { ut_a(UT_LIST_GET_PREV(LRU, bpage)->old == old); } #endif /* UNIV_LRU_DEBUG */ bpage->old = old; } /************************************************************************* Determine if a block has been accessed in the buffer pool. */ UNIV_INLINE ibool buf_page_is_accessed( /*=================*/ /* out: TRUE if accessed */ const buf_page_t* bpage) /* in: control block */ { ut_ad(buf_page_in_file(bpage)); return(bpage->accessed); } /************************************************************************* Flag a block accessed. */ UNIV_INLINE void buf_page_set_accessed( /*==================*/ buf_page_t* bpage, /* in/out: control block */ ibool accessed) /* in: accessed */ { ut_a(buf_page_in_file(bpage)); ut_ad(mutex_own(buf_page_get_mutex(bpage))); bpage->accessed = accessed; } /************************************************************************* Gets the buf_block_t handle of a buffered file block if an uncompressed page frame exists, or NULL. */ UNIV_INLINE buf_block_t* buf_page_get_block( /*===============*/ /* out: control block, or NULL */ buf_page_t* bpage) /* in: control block, or NULL */ { if (UNIV_LIKELY(bpage != NULL)) { ut_ad(buf_page_in_file(bpage)); if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE) { return((buf_block_t*) bpage); } } return(NULL); } #ifdef UNIV_DEBUG /************************************************************************* Gets a pointer to the memory frame of a block. */ UNIV_INLINE buf_frame_t* buf_block_get_frame( /*================*/ /* out: pointer to the frame */ const buf_block_t* block) /* in: pointer to the control block */ { ut_ad(block); switch (buf_block_get_state(block)) { case BUF_BLOCK_ZIP_FREE: case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_DIRTY: case BUF_BLOCK_NOT_USED: ut_error; break; case BUF_BLOCK_FILE_PAGE: ut_a(block->page.buf_fix_count > 0); /* fall through */ case BUF_BLOCK_READY_FOR_USE: case BUF_BLOCK_MEMORY: case BUF_BLOCK_REMOVE_HASH: goto ok; } ut_error; ok: return((buf_frame_t*) block->frame); } #endif /* UNIV_DEBUG */ /************************************************************************* Gets the space id of a block. */ UNIV_INLINE ulint buf_page_get_space( /*===============*/ /* out: space id */ const buf_page_t* bpage) /* in: pointer to the control block */ { ut_ad(bpage); ut_a(buf_page_in_file(bpage)); return(bpage->space); } /************************************************************************* Gets the space id of a block. */ UNIV_INLINE ulint buf_block_get_space( /*================*/ /* out: space id */ const buf_block_t* block) /* in: pointer to the control block */ { ut_ad(block); ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); return(block->page.space); } /************************************************************************* Gets the page number of a block. */ UNIV_INLINE ulint buf_page_get_page_no( /*=================*/ /* out: page number */ const buf_page_t* bpage) /* in: pointer to the control block */ { ut_ad(bpage); ut_a(buf_page_in_file(bpage)); return(bpage->offset); } /************************************************************************* Gets the page number of a block. */ UNIV_INLINE ulint buf_block_get_page_no( /*==================*/ /* out: page number */ const buf_block_t* block) /* in: pointer to the control block */ { ut_ad(block); ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); return(block->page.offset); } /************************************************************************* Gets the compressed page size of a block. */ UNIV_INLINE ulint buf_page_get_zip_size( /*==================*/ /* out: compressed page size, or 0 */ const buf_page_t* bpage) /* in: pointer to the control block */ { return(bpage->zip.ssize ? 512 << bpage->zip.ssize : 0); } /************************************************************************* Gets the compressed page size of a block. */ UNIV_INLINE ulint buf_block_get_zip_size( /*===================*/ /* out: compressed page size, or 0 */ const buf_block_t* block) /* in: pointer to the control block */ { return(block->page.zip.ssize ? 512 << block->page.zip.ssize : 0); } #if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG /*********************************************************************** Gets the block to whose frame the pointer is pointing to. */ UNIV_INLINE const buf_block_t* buf_block_align( /*============*/ /* out: pointer to block */ const byte* ptr) /* in: pointer to a frame */ { const buf_block_t* block; ulint space_id, page_no; ptr = (const byte*) ut_align_down(ptr, UNIV_PAGE_SIZE); page_no = mach_read_from_4(ptr + FIL_PAGE_OFFSET); space_id = mach_read_from_4(ptr + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); block = (const buf_block_t*) buf_page_hash_get(space_id, page_no); ut_ad(block); ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); ut_ad(block->frame == ptr); return(block); } /************************************************************************* Gets the compressed page descriptor corresponding to an uncompressed page if applicable. */ UNIV_INLINE const page_zip_des_t* buf_frame_get_page_zip( /*===================*/ /* out: compressed page descriptor, or NULL */ const byte* ptr) /* in: pointer to the page */ { const page_zip_des_t* page_zip; buf_pool_mutex_enter(); page_zip = buf_block_get_page_zip(buf_block_align(ptr)); buf_pool_mutex_exit(); return(page_zip); } #endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */ /************************************************************************** Gets the space id, page offset, and byte offset within page of a pointer pointing to a buffer frame containing a file page. */ UNIV_INLINE void buf_ptr_get_fsp_addr( /*=================*/ const void* ptr, /* in: pointer to a buffer frame */ ulint* space, /* out: space id */ fil_addr_t* addr) /* out: page offset and byte offset */ { const page_t* page = (const page_t*) ut_align_down(ptr, UNIV_PAGE_SIZE); *space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); addr->page = mach_read_from_4(page + FIL_PAGE_OFFSET); addr->boffset = ut_align_offset(ptr, UNIV_PAGE_SIZE); } /************************************************************************** Gets the hash value of the page the pointer is pointing to. This can be used in searches in the lock hash table. */ UNIV_INLINE ulint buf_block_get_lock_hash_val( /*========================*/ /* out: lock hash value */ const buf_block_t* block) /* in: block */ { return(block->lock_hash_val); } /************************************************************************ Allocates a buffer block. */ UNIV_INLINE buf_block_t* buf_block_alloc( /*============*/ /* out, own: the allocated block, in state BUF_BLOCK_MEMORY */ ulint zip_size) /* in: compressed page size in bytes, or 0 if uncompressed tablespace */ { buf_block_t* block; block = buf_LRU_get_free_block(zip_size); buf_block_set_state(block, BUF_BLOCK_MEMORY); return(block); } /************************************************************************ Frees a buffer block which does not contain a file page. */ UNIV_INLINE void buf_block_free( /*===========*/ buf_block_t* block) /* in, own: block to be freed */ { buf_pool_mutex_enter(); mutex_enter(&block->mutex); ut_a(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE); buf_LRU_block_free_non_file_page(block); mutex_exit(&block->mutex); buf_pool_mutex_exit(); } /************************************************************************* Copies contents of a buffer frame to a given buffer. */ UNIV_INLINE byte* buf_frame_copy( /*===========*/ /* out: buf */ byte* buf, /* in: buffer to copy to */ const buf_frame_t* frame) /* in: buffer frame */ { ut_ad(buf && frame); ut_memcpy(buf, frame, UNIV_PAGE_SIZE); return(buf); } /************************************************************************ Calculates a folded value of a file page address to use in the page hash table. */ UNIV_INLINE ulint buf_page_address_fold( /*==================*/ /* out: the folded value */ ulint space, /* in: space id */ ulint offset) /* in: offset of the page within space */ { return((space << 20) + space + offset); } /************************************************************************ This function is used to get info if there is an io operation going on on a buffer page. */ UNIV_INLINE ibool buf_page_io_query( /*==============*/ /* out: TRUE if io going on */ buf_page_t* bpage) /* in: buf_pool block, must be bufferfixed */ { ibool io_fixed; buf_pool_mutex_enter(); ut_ad(buf_page_in_file(bpage)); ut_ad(bpage->buf_fix_count > 0); io_fixed = buf_page_get_io_fix(bpage) != BUF_IO_NONE; buf_pool_mutex_exit(); return(io_fixed); } /************************************************************************ Gets the youngest modification log sequence number for a frame. Returns zero if not file page or no modification occurred yet. */ UNIV_INLINE ib_uint64_t buf_page_get_newest_modification( /*=============================*/ /* out: newest modification to page */ const buf_page_t* bpage) /* in: block containing the page frame */ { ib_uint64_t lsn; buf_pool_mutex_enter(); if (buf_page_in_file(bpage)) { lsn = bpage->newest_modification; } else { lsn = 0; } buf_pool_mutex_exit(); return(lsn); } /************************************************************************ Increments the modify clock of a frame by 1. The caller must (1) own the buf_pool mutex and block bufferfix count has to be zero, (2) or own an x-lock on the block. */ UNIV_INLINE void buf_block_modify_clock_inc( /*=======================*/ buf_block_t* block) /* in: block */ { #ifdef UNIV_SYNC_DEBUG ut_ad((buf_pool_mutex_own() && (block->page.buf_fix_count == 0)) || rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE)); #endif /* UNIV_SYNC_DEBUG */ block->modify_clock++; } /************************************************************************ Returns the value of the modify clock. The caller must have an s-lock or x-lock on the block. */ UNIV_INLINE ib_uint64_t buf_block_get_modify_clock( /*=======================*/ /* out: value */ buf_block_t* block) /* in: block */ { #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED) || rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE)); #endif /* UNIV_SYNC_DEBUG */ return(block->modify_clock); } /*********************************************************************** Increments the bufferfix count. */ UNIV_INLINE void buf_block_buf_fix_inc_func( /*=======================*/ #ifdef UNIV_SYNC_DEBUG const char* file, /* in: file name */ ulint line, /* in: line */ #endif /* UNIV_SYNC_DEBUG */ buf_block_t* block) /* in: block to bufferfix */ { #ifdef UNIV_SYNC_DEBUG ibool ret; ret = rw_lock_s_lock_func_nowait(&(block->debug_latch), file, line); ut_a(ret); #endif /* UNIV_SYNC_DEBUG */ ut_ad(mutex_own(&block->mutex)); block->page.buf_fix_count++; } #ifdef UNIV_SYNC_DEBUG # define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b) #else /* UNIV_SYNC_DEBUG */ # define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b) #endif /* UNIV_SYNC_DEBUG */ /*********************************************************************** Decrements the bufferfix count. */ UNIV_INLINE void buf_block_buf_fix_dec( /*==================*/ buf_block_t* block) /* in: block to bufferunfix */ { ut_ad(mutex_own(&block->mutex)); block->page.buf_fix_count--; #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&block->debug_latch); #endif } /********************************************************************** Returns the control block of a file page, NULL if not found. */ UNIV_INLINE buf_page_t* buf_page_hash_get( /*==============*/ /* out: block, NULL if not found */ ulint space, /* in: space id */ ulint offset) /* in: offset of the page within space */ { buf_page_t* bpage; ulint fold; ut_ad(buf_pool); ut_ad(buf_pool_mutex_own()); /* Look for the page in the hash table */ fold = buf_page_address_fold(space, offset); HASH_SEARCH(hash, buf_pool->page_hash, fold, buf_page_t*, bpage, bpage->space == space && bpage->offset == offset); if (bpage) { ut_a(buf_page_in_file(bpage)); ut_ad(bpage->in_page_hash); ut_ad(!bpage->in_zip_hash); UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage); } return(bpage); } /********************************************************************** Returns the control block of a file page, NULL if not found or an uncompressed page frame does not exist. */ UNIV_INLINE buf_block_t* buf_block_hash_get( /*===============*/ /* out: block, NULL if not found */ ulint space, /* in: space id */ ulint offset) /* in: offset of the page within space */ { return(buf_page_get_block(buf_page_hash_get(space, offset))); } /************************************************************************ Returns TRUE if the page can be found in the buffer pool hash table. NOTE that it is possible that the page is not yet read from disk, though. */ UNIV_INLINE ibool buf_page_peek( /*==========*/ /* out: TRUE if found from page hash table, NOTE that the page is not necessarily yet read from disk! */ ulint space, /* in: space id */ ulint offset) /* in: page number */ { const buf_page_t* bpage; buf_pool_mutex_enter(); bpage = buf_page_hash_get(space, offset); buf_pool_mutex_exit(); return(bpage != NULL); } /************************************************************************ Releases a compressed-only page acquired with buf_page_get_zip(). */ UNIV_INLINE void buf_page_release_zip( /*=================*/ buf_page_t* bpage) /* in: buffer block */ { buf_block_t* block; ut_ad(bpage); ut_a(bpage->buf_fix_count > 0); switch (buf_page_get_state(bpage)) { case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_DIRTY: mutex_enter(&buf_pool_zip_mutex); bpage->buf_fix_count--; mutex_exit(&buf_pool_zip_mutex); return; case BUF_BLOCK_FILE_PAGE: block = (buf_block_t*) bpage; mutex_enter(&block->mutex); #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&block->debug_latch); #endif bpage->buf_fix_count--; mutex_exit(&block->mutex); return; case BUF_BLOCK_ZIP_FREE: case BUF_BLOCK_NOT_USED: case BUF_BLOCK_READY_FOR_USE: case BUF_BLOCK_MEMORY: case BUF_BLOCK_REMOVE_HASH: break; } ut_error; } /************************************************************************ Decrements the bufferfix count of a buffer control block and releases a latch, if specified. */ UNIV_INLINE void buf_page_release( /*=============*/ buf_block_t* block, /* in: buffer block */ ulint rw_latch, /* in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ mtr_t* mtr) /* in: mtr */ { ut_ad(block); ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); ut_a(block->page.buf_fix_count > 0); if (rw_latch == RW_X_LATCH && mtr->modifications) { buf_pool_mutex_enter(); buf_flush_note_modification(block, mtr); buf_pool_mutex_exit(); } mutex_enter(&block->mutex); #ifdef UNIV_SYNC_DEBUG rw_lock_s_unlock(&(block->debug_latch)); #endif block->page.buf_fix_count--; mutex_exit(&block->mutex); if (rw_latch == RW_S_LATCH) { rw_lock_s_unlock(&(block->lock)); } else if (rw_latch == RW_X_LATCH) { rw_lock_x_unlock(&(block->lock)); } } #ifdef UNIV_SYNC_DEBUG /************************************************************************* Adds latch level info for the rw-lock protecting the buffer frame. This should be called in the debug version after a successful latching of a page if we know the latching order level of the acquired latch. */ UNIV_INLINE void buf_block_dbg_add_level( /*====================*/ buf_block_t* block, /* in: buffer page where we have acquired latch */ ulint level) /* in: latching order level */ { sync_thread_add_level(&block->lock, level); } #endif /* UNIV_SYNC_DEBUG */