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 | |