| 1 | /***************************************************************************** |
| 2 | |
| 3 | Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. |
| 4 | Copyright (c) 2017, 2018, MariaDB Corporation. |
| 5 | |
| 6 | This program is free software; you can redistribute it and/or modify it under |
| 7 | the terms of the GNU General Public License as published by the Free Software |
| 8 | Foundation; version 2 of the License. |
| 9 | |
| 10 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU General Public License along with |
| 15 | this program; if not, write to the Free Software Foundation, Inc., |
| 16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
| 17 | |
| 18 | *****************************************************************************/ |
| 19 | |
| 20 | /**************************************************//** |
| 21 | @file include/buf0lru.h |
| 22 | The database buffer pool LRU replacement algorithm |
| 23 | |
| 24 | Created 11/5/1995 Heikki Tuuri |
| 25 | *******************************************************/ |
| 26 | |
| 27 | #ifndef buf0lru_h |
| 28 | #define buf0lru_h |
| 29 | |
| 30 | #include "univ.i" |
| 31 | #include "ut0byte.h" |
| 32 | #include "buf0types.h" |
| 33 | |
| 34 | // Forward declaration |
| 35 | struct trx_t; |
| 36 | struct fil_space_t; |
| 37 | |
| 38 | /******************************************************************//** |
| 39 | Returns TRUE if less than 25 % of the buffer pool is available. This can be |
| 40 | used in heuristics to prevent huge transactions eating up the whole buffer |
| 41 | pool for their locks. |
| 42 | @return TRUE if less than 25 % of buffer pool left */ |
| 43 | ibool |
| 44 | buf_LRU_buf_pool_running_out(void); |
| 45 | /*==============================*/ |
| 46 | |
| 47 | /*####################################################################### |
| 48 | These are low-level functions |
| 49 | #########################################################################*/ |
| 50 | |
| 51 | /** Minimum LRU list length for which the LRU_old pointer is defined */ |
| 52 | #define BUF_LRU_OLD_MIN_LEN 512 /* 8 megabytes of 16k pages */ |
| 53 | |
| 54 | /** Empty the flush list for all pages belonging to a tablespace. |
| 55 | @param[in] id tablespace identifier |
| 56 | @param[in,out] observer flush observer, |
| 57 | or NULL if nothing is to be written */ |
| 58 | void |
| 59 | buf_LRU_flush_or_remove_pages( |
| 60 | ulint id, |
| 61 | FlushObserver* observer |
| 62 | #ifdef BTR_CUR_HASH_ADAPT |
| 63 | , bool drop_ahi = false /*!< whether to drop the adaptive hash index */ |
| 64 | #endif /* BTR_CUR_HASH_ADAPT */ |
| 65 | ); |
| 66 | |
| 67 | #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG |
| 68 | /********************************************************************//** |
| 69 | Insert a compressed block into buf_pool->zip_clean in the LRU order. */ |
| 70 | void |
| 71 | buf_LRU_insert_zip_clean( |
| 72 | /*=====================*/ |
| 73 | buf_page_t* bpage); /*!< in: pointer to the block in question */ |
| 74 | #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ |
| 75 | |
| 76 | /******************************************************************//** |
| 77 | Try to free a block. If bpage is a descriptor of a compressed-only |
| 78 | page, the descriptor object will be freed as well. |
| 79 | |
| 80 | NOTE: If this function returns true, it will temporarily |
| 81 | release buf_pool->mutex. Furthermore, the page frame will no longer be |
| 82 | accessible via bpage. |
| 83 | |
| 84 | The caller must hold buf_pool->mutex and must not hold any |
| 85 | buf_page_get_mutex() when calling this function. |
| 86 | @return true if freed, false otherwise. */ |
| 87 | bool |
| 88 | buf_LRU_free_page( |
| 89 | /*==============*/ |
| 90 | buf_page_t* bpage, /*!< in: block to be freed */ |
| 91 | bool zip) /*!< in: true if should remove also the |
| 92 | compressed page of an uncompressed page */ |
| 93 | MY_ATTRIBUTE((nonnull)); |
| 94 | /******************************************************************//** |
| 95 | Try to free a replaceable block. |
| 96 | @return true if found and freed */ |
| 97 | bool |
| 98 | buf_LRU_scan_and_free_block( |
| 99 | /*========================*/ |
| 100 | buf_pool_t* buf_pool, /*!< in: buffer pool instance */ |
| 101 | bool scan_all) /*!< in: scan whole LRU list |
| 102 | if true, otherwise scan only |
| 103 | 'old' blocks. */ |
| 104 | MY_ATTRIBUTE((nonnull,warn_unused_result)); |
| 105 | /******************************************************************//** |
| 106 | Returns a free block from the buf_pool. The block is taken off the |
| 107 | free list. If it is empty, returns NULL. |
| 108 | @return a free control block, or NULL if the buf_block->free list is empty */ |
| 109 | buf_block_t* |
| 110 | buf_LRU_get_free_only( |
| 111 | /*==================*/ |
| 112 | buf_pool_t* buf_pool); /*!< buffer pool instance */ |
| 113 | /******************************************************************//** |
| 114 | Returns a free block from the buf_pool. The block is taken off the |
| 115 | free list. If free list is empty, blocks are moved from the end of the |
| 116 | LRU list to the free list. |
| 117 | This function is called from a user thread when it needs a clean |
| 118 | block to read in a page. Note that we only ever get a block from |
| 119 | the free list. Even when we flush a page or find a page in LRU scan |
| 120 | we put it to free list to be used. |
| 121 | * iteration 0: |
| 122 | * get a block from free list, success:done |
| 123 | * if buf_pool->try_LRU_scan is set |
| 124 | * scan LRU up to srv_LRU_scan_depth to find a clean block |
| 125 | * the above will put the block on free list |
| 126 | * success:retry the free list |
| 127 | * flush one dirty page from tail of LRU to disk |
| 128 | * the above will put the block on free list |
| 129 | * success: retry the free list |
| 130 | * iteration 1: |
| 131 | * same as iteration 0 except: |
| 132 | * scan whole LRU list |
| 133 | * scan LRU list even if buf_pool->try_LRU_scan is not set |
| 134 | * iteration > 1: |
| 135 | * same as iteration 1 but sleep 10ms |
| 136 | @return the free control block, in state BUF_BLOCK_READY_FOR_USE */ |
| 137 | buf_block_t* |
| 138 | buf_LRU_get_free_block( |
| 139 | /*===================*/ |
| 140 | buf_pool_t* buf_pool) /*!< in/out: buffer pool instance */ |
| 141 | MY_ATTRIBUTE((nonnull,warn_unused_result)); |
| 142 | /******************************************************************//** |
| 143 | Determines if the unzip_LRU list should be used for evicting a victim |
| 144 | instead of the general LRU list. |
| 145 | @return TRUE if should use unzip_LRU */ |
| 146 | ibool |
| 147 | buf_LRU_evict_from_unzip_LRU( |
| 148 | /*=========================*/ |
| 149 | buf_pool_t* buf_pool); |
| 150 | /******************************************************************//** |
| 151 | Puts a block back to the free list. */ |
| 152 | void |
| 153 | buf_LRU_block_free_non_file_page( |
| 154 | /*=============================*/ |
| 155 | buf_block_t* block); /*!< in: block, must not contain a file page */ |
| 156 | /******************************************************************//** |
| 157 | Adds a block to the LRU list. Please make sure that the page_size is |
| 158 | already set when invoking the function, so that we can get correct |
| 159 | page_size from the buffer page when adding a block into LRU */ |
| 160 | void |
| 161 | buf_LRU_add_block( |
| 162 | /*==============*/ |
| 163 | buf_page_t* bpage, /*!< in: control block */ |
| 164 | ibool old); /*!< in: TRUE if should be put to the old |
| 165 | blocks in the LRU list, else put to the |
| 166 | start; if the LRU list is very short, added to |
| 167 | the start regardless of this parameter */ |
| 168 | /******************************************************************//** |
| 169 | Adds a block to the LRU list of decompressed zip pages. */ |
| 170 | void |
| 171 | buf_unzip_LRU_add_block( |
| 172 | /*====================*/ |
| 173 | buf_block_t* block, /*!< in: control block */ |
| 174 | ibool old); /*!< in: TRUE if should be put to the end |
| 175 | of the list, else put to the start */ |
| 176 | /******************************************************************//** |
| 177 | Moves a block to the start of the LRU list. */ |
| 178 | void |
| 179 | buf_LRU_make_block_young( |
| 180 | /*=====================*/ |
| 181 | buf_page_t* bpage); /*!< in: control block */ |
| 182 | /**********************************************************************//** |
| 183 | Updates buf_pool->LRU_old_ratio. |
| 184 | @return updated old_pct */ |
| 185 | uint |
| 186 | buf_LRU_old_ratio_update( |
| 187 | /*=====================*/ |
| 188 | uint old_pct,/*!< in: Reserve this percentage of |
| 189 | the buffer pool for "old" blocks. */ |
| 190 | ibool adjust);/*!< in: TRUE=adjust the LRU list; |
| 191 | FALSE=just assign buf_pool->LRU_old_ratio |
| 192 | during the initialization of InnoDB */ |
| 193 | /********************************************************************//** |
| 194 | Update the historical stats that we are collecting for LRU eviction |
| 195 | policy at the end of each interval. */ |
| 196 | void |
| 197 | buf_LRU_stat_update(void); |
| 198 | /*=====================*/ |
| 199 | |
| 200 | /******************************************************************//** |
| 201 | Remove one page from LRU list and put it to free list */ |
| 202 | void |
| 203 | buf_LRU_free_one_page( |
| 204 | /*==================*/ |
| 205 | buf_page_t* bpage) /*!< in/out: block, must contain a file page and |
| 206 | be in a state where it can be freed; there |
| 207 | may or may not be a hash index to the page */ |
| 208 | MY_ATTRIBUTE((nonnull)); |
| 209 | |
| 210 | /******************************************************************//** |
| 211 | Adjust LRU hazard pointers if needed. */ |
| 212 | void |
| 213 | buf_LRU_adjust_hp( |
| 214 | /*==============*/ |
| 215 | buf_pool_t* buf_pool,/*!< in: buffer pool instance */ |
| 216 | const buf_page_t* bpage); /*!< in: control block */ |
| 217 | |
| 218 | #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG |
| 219 | /**********************************************************************//** |
| 220 | Validates the LRU list. |
| 221 | @return TRUE */ |
| 222 | ibool |
| 223 | buf_LRU_validate(void); |
| 224 | /*==================*/ |
| 225 | #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ |
| 226 | #if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG |
| 227 | /**********************************************************************//** |
| 228 | Prints the LRU list. */ |
| 229 | void |
| 230 | buf_LRU_print(void); |
| 231 | /*===============*/ |
| 232 | #endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */ |
| 233 | |
| 234 | /** @name Heuristics for detecting index scan @{ */ |
| 235 | /** The denominator of buf_pool->LRU_old_ratio. */ |
| 236 | #define BUF_LRU_OLD_RATIO_DIV 1024 |
| 237 | /** Maximum value of buf_pool->LRU_old_ratio. |
| 238 | @see buf_LRU_old_adjust_len |
| 239 | @see buf_pool->LRU_old_ratio_update */ |
| 240 | #define BUF_LRU_OLD_RATIO_MAX BUF_LRU_OLD_RATIO_DIV |
| 241 | /** Minimum value of buf_pool->LRU_old_ratio. |
| 242 | @see buf_LRU_old_adjust_len |
| 243 | @see buf_pool->LRU_old_ratio_update |
| 244 | The minimum must exceed |
| 245 | (BUF_LRU_OLD_TOLERANCE + 5) * BUF_LRU_OLD_RATIO_DIV / BUF_LRU_OLD_MIN_LEN. */ |
| 246 | #define BUF_LRU_OLD_RATIO_MIN 51 |
| 247 | |
| 248 | #if BUF_LRU_OLD_RATIO_MIN >= BUF_LRU_OLD_RATIO_MAX |
| 249 | # error "BUF_LRU_OLD_RATIO_MIN >= BUF_LRU_OLD_RATIO_MAX" |
| 250 | #endif |
| 251 | #if BUF_LRU_OLD_RATIO_MAX > BUF_LRU_OLD_RATIO_DIV |
| 252 | # error "BUF_LRU_OLD_RATIO_MAX > BUF_LRU_OLD_RATIO_DIV" |
| 253 | #endif |
| 254 | |
| 255 | /** Move blocks to "new" LRU list only if the first access was at |
| 256 | least this many milliseconds ago. Not protected by any mutex or latch. */ |
| 257 | extern uint buf_LRU_old_threshold_ms; |
| 258 | /* @} */ |
| 259 | |
| 260 | /** @brief Statistics for selecting the LRU list for eviction. |
| 261 | |
| 262 | These statistics are not 'of' LRU but 'for' LRU. We keep count of I/O |
| 263 | and page_zip_decompress() operations. Based on the statistics we decide |
| 264 | if we want to evict from buf_pool->unzip_LRU or buf_pool->LRU. */ |
| 265 | struct buf_LRU_stat_t |
| 266 | { |
| 267 | ulint io; /**< Counter of buffer pool I/O operations. */ |
| 268 | ulint unzip; /**< Counter of page_zip_decompress operations. */ |
| 269 | }; |
| 270 | |
| 271 | /** Current operation counters. Not protected by any mutex. |
| 272 | Cleared by buf_LRU_stat_update(). */ |
| 273 | extern buf_LRU_stat_t buf_LRU_stat_cur; |
| 274 | |
| 275 | /** Running sum of past values of buf_LRU_stat_cur. |
| 276 | Updated by buf_LRU_stat_update(). Protected by buf_pool->mutex. */ |
| 277 | extern buf_LRU_stat_t buf_LRU_stat_sum; |
| 278 | |
| 279 | /********************************************************************//** |
| 280 | Increments the I/O counter in buf_LRU_stat_cur. */ |
| 281 | #define buf_LRU_stat_inc_io() buf_LRU_stat_cur.io++ |
| 282 | /********************************************************************//** |
| 283 | Increments the page_zip_decompress() counter in buf_LRU_stat_cur. */ |
| 284 | #define buf_LRU_stat_inc_unzip() buf_LRU_stat_cur.unzip++ |
| 285 | |
| 286 | #endif |
| 287 | |