1 /***************************************************************************** 2 3 Copyright (c) 1995, 2020, Oracle and/or its affiliates. All Rights Reserved. 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License, version 2.0, as published by the 7 Free Software Foundation. 8 9 This program is also distributed with certain software (including but not 10 limited to OpenSSL) that is licensed under separate terms, as designated in a 11 particular file or component or in included license documentation. The authors 12 of MySQL hereby grant you an additional permission to link the program and 13 your derivative works with the separately licensed software that they have 14 included with MySQL. 15 16 This program is distributed in the hope that it will be useful, but WITHOUT 17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, 19 for more details. 20 21 You should have received a copy of the GNU General Public License along with 22 this program; if not, write to the Free Software Foundation, Inc., 23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 25 *****************************************************************************/ 26 27 /** @file include/buf0flu.h 28 The database buffer pool flush algorithm 29 30 Created 11/5/1995 Heikki Tuuri 31 *******************************************************/ 32 33 #ifndef buf0flu_h 34 #define buf0flu_h 35 36 #include "buf0types.h" 37 #include "log0log.h" 38 #include "univ.i" 39 #include "ut0byte.h" 40 41 #ifndef UNIV_HOTBACKUP 42 /** Checks if the page_cleaner is in active state. */ 43 bool buf_flush_page_cleaner_is_active(); 44 45 #ifdef UNIV_DEBUG 46 47 /** Value of MySQL global variable used to disable page cleaner. */ 48 extern bool innodb_page_cleaner_disabled_debug; 49 50 #endif /* UNIV_DEBUG */ 51 52 /** Event to synchronise with the flushing. */ 53 extern os_event_t buf_flush_event; 54 55 class ut_stage_alter_t; 56 57 /** Remove a block from the flush list of modified blocks. 58 @param[in] bpage pointer to the block in question */ 59 void buf_flush_remove(buf_page_t *bpage); 60 61 /** Relocates a buffer control block on the flush_list. 62 Note that it is assumed that the contents of bpage has already been 63 copied to dpage. */ 64 void buf_flush_relocate_on_flush_list( 65 buf_page_t *bpage, /*!< in/out: control block being moved */ 66 buf_page_t *dpage); /*!< in/out: destination block */ 67 68 /** Updates the flush system data structures when a write is completed. 69 @param[in] bpage pointer to the block in question */ 70 void buf_flush_write_complete(buf_page_t *bpage); 71 72 #endif /* !UNIV_HOTBACKUP */ 73 74 /** Check if page type is uncompressed. 75 @param[in] page page frame 76 @return true if uncompressed page type. */ 77 bool page_is_uncompressed_type(const byte *page); 78 79 /** Initialize a page for writing to the tablespace. 80 @param[in] block buffer block; NULL if bypassing the buffer pool 81 @param[in,out] page page frame 82 @param[in,out] page_zip_ compressed page, or NULL if uncompressed 83 @param[in] newest_lsn newest modification LSN to the page 84 @param[in] skip_checksum whether to disable the page checksum 85 @param[in] skip_lsn_check true to skip check for lsn (in DEBUG) */ 86 void buf_flush_init_for_writing(const buf_block_t *block, byte *page, 87 void *page_zip_, lsn_t newest_lsn, 88 bool skip_checksum, bool skip_lsn_check); 89 90 #ifndef UNIV_HOTBACKUP 91 #if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG 92 /** Writes a flushable page asynchronously from the buffer pool to a file. 93 NOTE: block and LRU list mutexes must be held upon entering this function, and 94 they will be released by this function after flushing. This is loosely based on 95 buf_flush_batch() and buf_flush_page(). 96 @param[in,out] buf_pool buffer pool instance 97 @param[in,out] block buffer control block 98 @return true if the page was flushed and the mutex released */ 99 bool buf_flush_page_try(buf_pool_t *buf_pool, buf_block_t *block) 100 MY_ATTRIBUTE((warn_unused_result)); 101 #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ 102 /** Do flushing batch of a given type. 103 NOTE: The calling thread is not allowed to own any latches on pages! 104 @param[in,out] buf_pool buffer pool instance 105 @param[in] type flush type 106 @param[in] min_n wished minimum mumber of blocks flushed 107 (it is not guaranteed that the actual number is that big, though) 108 @param[in] lsn_limit in the case BUF_FLUSH_LIST all blocks whose 109 oldest_modification is smaller than this should be flushed (if their number 110 does not exceed min_n), otherwise ignored 111 @param[out] n_processed the number of pages which were processed is 112 passed back to caller. Ignored if NULL 113 @retval true if a batch was queued successfully. 114 @retval false if another batch of same type was already running. */ 115 bool buf_flush_do_batch(buf_pool_t *buf_pool, buf_flush_t type, ulint min_n, 116 lsn_t lsn_limit, ulint *n_processed); 117 118 /** This utility flushes dirty blocks from the end of the flush list of all 119 buffer pool instances. 120 NOTE: The calling thread is not allowed to own any latches on pages! 121 @param[in] min_n wished minimum mumber of blocks flushed (it is 122 not guaranteed that the actual number is that big, though) 123 @param[in] lsn_limit in the case BUF_FLUSH_LIST all blocks whose 124 oldest_modification is smaller than this should be flushed (if their number 125 does not exceed min_n), otherwise ignored 126 @param[out] n_processed the number of pages which were processed is 127 passed back to caller. Ignored if NULL. 128 @return true if a batch was queued successfully for each buffer pool 129 instance. false if another batch of same type was already running in 130 at least one of the buffer pool instance */ 131 bool buf_flush_lists(ulint min_n, lsn_t lsn_limit, ulint *n_processed); 132 133 /** This function picks up a single page from the tail of the LRU 134 list, flushes it (if it is dirty), removes it from page_hash and LRU 135 list and puts it on the free list. It is called from user threads when 136 they are unable to find a replaceable page at the tail of the LRU 137 list i.e.: when the background LRU flushing in the page_cleaner thread 138 is not fast enough to keep pace with the workload. 139 @param[in,out] buf_pool buffer pool instance 140 @return true if success. */ 141 bool buf_flush_single_page_from_LRU(buf_pool_t *buf_pool); 142 143 /** Waits until a flush batch of the given type ends. 144 @param[in] buf_pool Buffer pool instance. 145 @param[in] flush_type Flush type. */ 146 void buf_flush_wait_batch_end(buf_pool_t *buf_pool, buf_flush_t flush_type); 147 148 /** Waits until a flush batch of the given type ends. This is called by a 149 thread that only wants to wait for a flush to end but doesn't do any flushing 150 itself. 151 @param[in] buf_pool buffer pool instance 152 @param[in] type BUF_FLUSH_LRU or BUF_FLUSH_LIST */ 153 void buf_flush_wait_batch_end_wait_only(buf_pool_t *buf_pool, buf_flush_t type); 154 155 /** This function should be called at a mini-transaction commit, if a page was 156 modified in it. Puts the block to the list of modified blocks, if it not 157 already in it. 158 @param[in] block block which is modified 159 @param[in] start_lsn start lsn of the first mtr in a set of mtr's 160 @param[in] end_lsn end lsn of the last mtr in the set of mtr's 161 @param[in] observer flush observer */ 162 UNIV_INLINE 163 void buf_flush_note_modification(buf_block_t *block, lsn_t start_lsn, 164 lsn_t end_lsn, FlushObserver *observer); 165 166 /** This function should be called when recovery has modified a buffer page. 167 @param[in] block block which is modified 168 @param[in] start_lsn start lsn of the first mtr in a set of mtr's 169 @param[in] end_lsn end lsn of the last mtr in the set of mtr's */ 170 UNIV_INLINE 171 void buf_flush_recv_note_modification(buf_block_t *block, lsn_t start_lsn, 172 lsn_t end_lsn); 173 174 /** Returns TRUE if the file page block is immediately suitable for replacement, 175 i.e., the transition FILE_PAGE => NOT_USED allowed. The caller must hold the 176 LRU list and block mutexes. 177 @param[in] bpage buffer control block, must be buf_page_in_file() and 178 in the LRU list 179 @return true if can replace immediately */ 180 ibool buf_flush_ready_for_replace(buf_page_t *bpage); 181 182 #ifdef UNIV_DEBUG 183 struct SYS_VAR; 184 185 /** Disables page cleaner threads (coordinator and workers). 186 It's used by: SET GLOBAL innodb_page_cleaner_disabled_debug = 1 (0). 187 @param[in] thd thread handle 188 @param[in] var pointer to system variable 189 @param[out] var_ptr where the formal string goes 190 @param[in] save immediate result from check function */ 191 void buf_flush_page_cleaner_disabled_debug_update(THD *thd, SYS_VAR *var, 192 void *var_ptr, 193 const void *save); 194 #endif /* UNIV_DEBUG */ 195 196 /** Initialize page_cleaner. 197 @param[in] n_page_cleaners Number of page cleaner threads to create */ 198 void buf_flush_page_cleaner_init(size_t n_page_cleaners); 199 200 /** Wait for any possible LRU flushes that are in progress to end. */ 201 void buf_flush_wait_LRU_batch_end(); 202 203 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG 204 /** Validates the flush list. 205 @return true if ok */ 206 bool buf_flush_validate(buf_pool_t *buf_pool); 207 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ 208 209 /** Initialize the red-black tree to speed up insertions into the flush_list 210 during recovery process. Should be called at the start of recovery 211 process before any page has been read/written. */ 212 void buf_flush_init_flush_rbt(void); 213 214 /** Frees up the red-black tree. */ 215 void buf_flush_free_flush_rbt(void); 216 217 /** Writes a flushable page asynchronously from the buffer pool to a file. 218 NOTE: 1. in simulated aio we must call os_aio_simulated_wake_handler_threads 219 after we have posted a batch of writes! 2. buf_page_get_mutex(bpage) must be 220 held upon entering this function. The LRU list mutex must be held if flush_type 221 == BUF_FLUSH_SINGLE_PAGE. Both mutexes will be released by this function if it 222 returns true. 223 @param[in] buf_pool buffer pool instance 224 @param[in] bpage buffer control block 225 @param[in] flush_type type of flush 226 @param[in] sync true if sync IO request 227 @return true if page was flushed */ 228 ibool buf_flush_page(buf_pool_t *buf_pool, buf_page_t *bpage, 229 buf_flush_t flush_type, bool sync); 230 231 /** Check if the block is modified and ready for flushing. 232 @param[in] bpage buffer control block, must be buf_page_in_file() 233 @param[in] flush_type type of flush 234 @return true if can flush immediately */ 235 bool buf_flush_ready_for_flush(buf_page_t *bpage, buf_flush_t flush_type) 236 MY_ATTRIBUTE((warn_unused_result)); 237 238 /** Check if there are any dirty pages that belong to a space id in the flush 239 list in a particular buffer pool. 240 @return number of dirty pages present in a single buffer pool */ 241 ulint buf_pool_get_dirty_pages_count( 242 buf_pool_t *buf_pool, /*!< in: buffer pool */ 243 space_id_t id, /*!< in: space id to check */ 244 FlushObserver *observer); /*!< in: flush observer to check */ 245 246 /** Synchronously flush dirty blocks from the end of the flush list of all 247 buffer pool instances. NOTE: The calling thread is not allowed to own any 248 latches on pages! */ 249 void buf_flush_sync_all_buf_pools(void); 250 251 /** Request IO burst and wake page_cleaner up. 252 @param[in] lsn_limit upper limit of LSN to be flushed 253 @return true if we requested higher lsn than ever requested so far */ 254 bool buf_flush_request_force(lsn_t lsn_limit); 255 256 /** Reset sync LSN if beyond current log sys LSN. Currently used when 257 redo logging is disabled. */ 258 void reset_buf_flush_sync_lsn(); 259 260 /** Checks if all flush lists are empty. It is supposed to be used in 261 single thread, during startup or shutdown. Hence it does not acquire 262 lock and it is caller's responsibility to guarantee that flush lists 263 are not changed in background. 264 @return true if all flush lists were empty. */ 265 bool buf_are_flush_lists_empty_validate(); 266 267 /** We use FlushObserver to track flushing of non-redo logged pages in bulk 268 create index(BtrBulk.cc).Since we disable redo logging during a index build, 269 we need to make sure that all dirty pages modifed by the index build are 270 flushed to disk before any redo logged operations go to the index. */ 271 272 class FlushObserver { 273 public: 274 /** Constructor 275 @param[in] space_id table space id 276 @param[in] trx trx instance 277 @param[in] stage performance schema accounting object, 278 used by ALTER TABLE. It is passed to log_preflush_pool_modified_pages() 279 for accounting. */ 280 FlushObserver(space_id_t space_id, trx_t *trx, ut_stage_alter_t *stage); 281 282 /** Deconstructor */ 283 ~FlushObserver(); 284 285 /** Check pages have been flushed and removed from the flush list 286 in a buffer pool instance. 287 @param[in] instance_no buffer pool instance no 288 @return true if the pages were removed from the flush list */ is_complete(ulint instance_no)289 bool is_complete(ulint instance_no) { 290 os_rmb; 291 return (m_flushed->at(instance_no) == m_removed->at(instance_no) || 292 m_interrupted); 293 } 294 295 /** Interrupt observer not to wait. */ interrupted()296 void interrupted() { m_interrupted = true; } 297 298 /** Check whether trx is interrupted 299 @return true if trx is interrupted */ 300 bool check_interrupted(); 301 302 /** Flush dirty pages. */ 303 void flush(); 304 305 /** Notify observer of flushing a page 306 @param[in] buf_pool buffer pool instance 307 @param[in] bpage buffer page to flush */ 308 void notify_flush(buf_pool_t *buf_pool, buf_page_t *bpage); 309 310 /** Notify observer of removing a page from flush list 311 @param[in] buf_pool buffer pool instance 312 @param[in] bpage buffer page flushed */ 313 void notify_remove(buf_pool_t *buf_pool, buf_page_t *bpage); 314 315 private: 316 /** Table space id */ 317 space_id_t m_space_id; 318 319 /** Trx instance */ 320 trx_t *m_trx; 321 322 /** Performance schema accounting object, used by ALTER TABLE. 323 If not NULL, then stage->begin_phase_flush() will be called initially, 324 specifying the number of pages to be attempted to be flushed and 325 subsequently, stage->inc() will be called for each page we attempt to 326 flush. */ 327 ut_stage_alter_t *m_stage; 328 329 /* Flush request sent */ 330 std::vector<ulint> *m_flushed; 331 332 /* Flush request finished */ 333 std::vector<ulint> *m_removed; 334 335 /* True if the operation was interrupted. */ 336 bool m_interrupted; 337 }; 338 339 #endif /* !UNIV_HOTBACKUP */ 340 341 #include "buf0flu.ic" 342 343 #endif 344