1/***************************************************************************** 2 3Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. 4Copyright (c) 2008, Google Inc. 5Copyright (c) 2014, 2020, MariaDB Corporation. 6 7Portions of this file contain modifications contributed and copyrighted by 8Google, Inc. Those modifications are gratefully acknowledged and are described 9briefly in the InnoDB documentation. The contributions by Google are 10incorporated with their permission, and subject to the conditions contained in 11the file COPYING.Google. 12 13This program is free software; you can redistribute it and/or modify it under 14the terms of the GNU General Public License as published by the Free Software 15Foundation; version 2 of the License. 16 17This program is distributed in the hope that it will be useful, but WITHOUT 18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 19FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 20 21You should have received a copy of the GNU General Public License along with 22this program; if not, write to the Free Software Foundation, Inc., 2351 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA 24 25*****************************************************************************/ 26 27/**************************************************//** 28@file include/buf0buf.ic 29The database buffer buf_pool 30 31Created 11/5/1995 Heikki Tuuri 32*******************************************************/ 33 34#include "mtr0mtr.h" 35#include "buf0flu.h" 36#include "buf0lru.h" 37#include "buf0rea.h" 38#include "fsp0types.h" 39 40/*********************************************************************//** 41Gets the current size of buffer buf_pool in bytes. 42@return size in bytes */ 43UNIV_INLINE 44ulint 45buf_pool_get_curr_size(void) 46/*========================*/ 47{ 48 return(srv_buf_pool_curr_size); 49} 50 51/********************************************************************//** 52Reads the freed_page_clock of a buffer block. 53@return freed_page_clock */ 54UNIV_INLINE 55unsigned 56buf_page_get_freed_page_clock( 57/*==========================*/ 58 const buf_page_t* bpage) /*!< in: block */ 59{ 60 /* This is sometimes read without holding buf_pool.mutex. */ 61 return(bpage->freed_page_clock); 62} 63 64/********************************************************************//** 65Reads the freed_page_clock of a buffer block. 66@return freed_page_clock */ 67UNIV_INLINE 68unsigned 69buf_block_get_freed_page_clock( 70/*===========================*/ 71 const buf_block_t* block) /*!< in: block */ 72{ 73 return(buf_page_get_freed_page_clock(&block->page)); 74} 75 76/** Determine if a block is still close enough to the MRU end of the LRU list 77meaning that it is not in danger of getting evicted and also implying 78that it has been accessed recently. 79The page must be either buffer-fixed, or its page hash must be locked. 80@param[in] bpage buffer pool page 81@return whether bpage is close to MRU end of LRU */ 82inline bool buf_page_peek_if_young(const buf_page_t *bpage) 83{ 84 /* FIXME: bpage->freed_page_clock is 31 bits */ 85 return((buf_pool.freed_page_clock & ((1UL << 31) - 1)) 86 < (bpage->freed_page_clock 87 + (buf_pool.curr_size 88 * (BUF_LRU_OLD_RATIO_DIV - buf_pool.LRU_old_ratio) 89 / (BUF_LRU_OLD_RATIO_DIV * 4)))); 90} 91 92/** Determine if a block should be moved to the start of the LRU list if 93there is danger of dropping from the buffer pool. 94@param[in] bpage buffer pool page 95@return true if bpage should be made younger */ 96inline bool buf_page_peek_if_too_old(const buf_page_t *bpage) 97{ 98 if (buf_pool.freed_page_clock == 0) { 99 /* If eviction has not started yet, do not update the 100 statistics or move blocks in the LRU list. This is 101 either the warm-up phase or an in-memory workload. */ 102 return(FALSE); 103 } else if (buf_LRU_old_threshold_ms && bpage->old) { 104 uint32_t access_time = bpage->is_accessed(); 105 106 /* It is possible that the below comparison returns an 107 unexpected result. 2^32 milliseconds pass in about 50 days, 108 so if the difference between ut_time_ms() and access_time 109 is e.g. 50 days + 15 ms, then the below will behave as if 110 it is 15 ms. This is known and fixing it would require to 111 increase buf_page_t::access_time from 32 to 64 bits. */ 112 if (access_time 113 && ((ib_uint32_t) (ut_time_ms() - access_time)) 114 >= buf_LRU_old_threshold_ms) { 115 return(TRUE); 116 } 117 118 buf_pool.stat.n_pages_not_made_young++; 119 return false; 120 } else { 121 return !buf_page_peek_if_young(bpage); 122 } 123} 124 125#ifdef UNIV_DEBUG 126/*********************************************************************//** 127Gets a pointer to the memory frame of a block. 128@return pointer to the frame */ 129UNIV_INLINE 130buf_frame_t* 131buf_block_get_frame( 132/*================*/ 133 const buf_block_t* block) /*!< in: pointer to the control block */ 134{ 135 if (!block) { 136 return NULL; 137 } 138 139 switch (block->page.state()) { 140 case BUF_BLOCK_ZIP_PAGE: 141 case BUF_BLOCK_NOT_USED: 142 ut_error; 143 break; 144 case BUF_BLOCK_FILE_PAGE: 145 ut_a(block->page.buf_fix_count()); 146 /* fall through */ 147 case BUF_BLOCK_MEMORY: 148 case BUF_BLOCK_REMOVE_HASH: 149 goto ok; 150 } 151 ut_error; 152ok: 153 return((buf_frame_t*) block->frame); 154} 155#endif /* UNIV_DEBUG */ 156 157/********************************************************************//** 158Allocates a buf_page_t descriptor. This function must succeed. In case 159of failure we assert in this function. 160@return: the allocated descriptor. */ 161UNIV_INLINE 162buf_page_t* 163buf_page_alloc_descriptor(void) 164/*===========================*/ 165{ 166 buf_page_t* bpage; 167 168 bpage = (buf_page_t*) ut_zalloc_nokey(sizeof *bpage); 169 ut_ad(bpage); 170 MEM_UNDEFINED(bpage, sizeof *bpage); 171 172 return(bpage); 173} 174 175/********************************************************************//** 176Free a buf_page_t descriptor. */ 177UNIV_INLINE 178void 179buf_page_free_descriptor( 180/*=====================*/ 181 buf_page_t* bpage) /*!< in: bpage descriptor to free. */ 182{ 183 ut_free(bpage); 184} 185 186/** Allocate a buffer block. 187@return own: the allocated block, in state BUF_BLOCK_MEMORY */ 188inline buf_block_t *buf_block_alloc() 189{ 190 return buf_LRU_get_free_block(false); 191} 192 193/********************************************************************//** 194Frees a buffer block which does not contain a file page. */ 195UNIV_INLINE 196void 197buf_block_free( 198/*===========*/ 199 buf_block_t* block) /*!< in, own: block to be freed */ 200{ 201 mysql_mutex_lock(&buf_pool.mutex); 202 buf_LRU_block_free_non_file_page(block); 203 mysql_mutex_unlock(&buf_pool.mutex); 204} 205 206/********************************************************************//** 207Increments the modify clock of a frame by 1. The caller must (1) own the 208buf_pool mutex and block bufferfix count has to be zero, (2) or own an x-lock 209on the block. */ 210UNIV_INLINE 211void 212buf_block_modify_clock_inc( 213/*=======================*/ 214 buf_block_t* block) /*!< in: block */ 215{ 216#ifdef SAFE_MUTEX 217 /* No latch is acquired for the shared temporary tablespace. */ 218 ut_ad(fsp_is_system_temporary(block->page.id().space()) 219 || (mysql_mutex_is_owner(&buf_pool.mutex) 220 && !block->page.buf_fix_count()) 221 || rw_lock_own_flagged(&block->lock, 222 RW_LOCK_FLAG_X | RW_LOCK_FLAG_SX)); 223#else /* SAFE_MUTEX */ 224 /* No latch is acquired for the shared temporary tablespace. */ 225 ut_ad(fsp_is_system_temporary(block->page.id().space()) 226 || !block->page.buf_fix_count() 227 || rw_lock_own_flagged(&block->lock, 228 RW_LOCK_FLAG_X | RW_LOCK_FLAG_SX)); 229#endif /* SAFE_MUTEX */ 230 assert_block_ahi_valid(block); 231 232 block->modify_clock++; 233} 234 235/********************************************************************//** 236Returns the value of the modify clock. The caller must have an s-lock 237or x-lock on the block. 238@return value */ 239UNIV_INLINE 240ib_uint64_t 241buf_block_get_modify_clock( 242/*=======================*/ 243 buf_block_t* block) /*!< in: block */ 244{ 245#ifdef UNIV_DEBUG 246 /* No latch is acquired for the shared temporary tablespace. */ 247 if (!fsp_is_system_temporary(block->page.id().space())) { 248 ut_ad(rw_lock_own(&(block->lock), RW_LOCK_S) 249 || rw_lock_own(&(block->lock), RW_LOCK_X) 250 || rw_lock_own(&(block->lock), RW_LOCK_SX)); 251 } 252#endif /* UNIV_DEBUG */ 253 254 return(block->modify_clock); 255} 256 257/*******************************************************************//** 258Increments the bufferfix count. */ 259UNIV_INLINE 260void 261buf_block_buf_fix_inc_func( 262/*=======================*/ 263#ifdef UNIV_DEBUG 264 const char* file, /*!< in: file name */ 265 unsigned line, /*!< in: line */ 266#endif /* UNIV_DEBUG */ 267 buf_block_t* block) /*!< in/out: block to bufferfix */ 268{ 269#ifdef UNIV_DEBUG 270 /* No debug latch is acquired if block belongs to system temporary. 271 Debug latch is not of much help if access to block is single 272 threaded. */ 273 if (!fsp_is_system_temporary(block->page.id().space())) { 274 ibool ret; 275 ret = rw_lock_s_lock_nowait(block->debug_latch, file, line); 276 ut_a(ret); 277 } 278#endif /* UNIV_DEBUG */ 279 280 block->fix(); 281} 282 283/*******************************************************************//** 284Decrements the bufferfix count. */ 285UNIV_INLINE 286void 287buf_block_buf_fix_dec( 288/*==================*/ 289 buf_block_t* block) /*!< in/out: block to bufferunfix */ 290{ 291#ifdef UNIV_DEBUG 292 /* No debug latch is acquired if block belongs to system temporary. 293 Debug latch is not of much help if access to block is single 294 threaded. */ 295 if (!fsp_is_system_temporary(block->page.id().space())) { 296 rw_lock_s_unlock(block->debug_latch); 297 } 298#endif /* UNIV_DEBUG */ 299 300 block->unfix(); 301} 302 303/********************************************************************//** 304Releases a compressed-only page acquired with buf_page_get_zip(). */ 305UNIV_INLINE 306void 307buf_page_release_zip( 308/*=================*/ 309 buf_page_t* bpage) /*!< in: buffer block */ 310{ 311 ut_ad(bpage); 312 ut_a(bpage->buf_fix_count()); 313 314 switch (bpage->state()) { 315 case BUF_BLOCK_FILE_PAGE: 316#ifdef UNIV_DEBUG 317 { 318 /* No debug latch is acquired if block belongs to system 319 temporary. Debug latch is not of much help if access to block 320 is single threaded. */ 321 buf_block_t* block = reinterpret_cast<buf_block_t*>(bpage); 322 if (!fsp_is_system_temporary(block->page.id().space())) { 323 rw_lock_s_unlock(block->debug_latch); 324 } 325 } 326#endif /* UNIV_DEBUG */ 327 /* Fall through */ 328 case BUF_BLOCK_ZIP_PAGE: 329 reinterpret_cast<buf_block_t*>(bpage)->unfix(); 330 return; 331 332 case BUF_BLOCK_NOT_USED: 333 case BUF_BLOCK_MEMORY: 334 case BUF_BLOCK_REMOVE_HASH: 335 break; 336 } 337 338 ut_error; 339} 340 341/********************************************************************//** 342Releases a latch, if specified. */ 343UNIV_INLINE 344void 345buf_page_release_latch( 346/*===================*/ 347 buf_block_t* block, /*!< in: buffer block */ 348 ulint rw_latch) /*!< in: RW_S_LATCH, RW_X_LATCH, 349 RW_NO_LATCH */ 350{ 351#ifdef UNIV_DEBUG 352 /* No debug latch is acquired if block belongs to system 353 temporary. Debug latch is not of much help if access to block 354 is single threaded. */ 355 if (!fsp_is_system_temporary(block->page.id().space())) { 356 rw_lock_s_unlock(block->debug_latch); 357 } 358#endif /* UNIV_DEBUG */ 359 360 if (rw_latch == RW_S_LATCH) { 361 rw_lock_s_unlock(&block->lock); 362 } else if (rw_latch == RW_SX_LATCH) { 363 rw_lock_sx_unlock(&block->lock); 364 } else if (rw_latch == RW_X_LATCH) { 365 rw_lock_x_unlock(&block->lock); 366 } 367} 368 369#ifdef UNIV_DEBUG 370/*********************************************************************//** 371Adds latch level info for the rw-lock protecting the buffer frame. This 372should be called in the debug version after a successful latching of a 373page if we know the latching order level of the acquired latch. */ 374UNIV_INLINE 375void 376buf_block_dbg_add_level( 377/*====================*/ 378 buf_block_t* block, /*!< in: buffer page 379 where we have acquired latch */ 380 latch_level_t level) /*!< in: latching order level */ 381{ 382 sync_check_lock(&block->lock, level); 383} 384#endif /* UNIV_DEBUG */ 385 386/********************************************************************//** 387Get buf frame. */ 388UNIV_INLINE 389void * 390buf_page_get_frame( 391/*===============*/ 392 const buf_page_t* bpage) /*!< in: buffer pool page */ 393{ 394 /* In encryption/compression buffer pool page may contain extra 395 buffer where result is stored. */ 396 if (bpage->slot && bpage->slot->out_buf) { 397 return bpage->slot->out_buf; 398 } else if (bpage->zip.data) { 399 return bpage->zip.data; 400 } else { 401 return ((buf_block_t*) bpage)->frame; 402 } 403} 404