1 /*****************************************************************************
2 
3 Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2014, 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, Fifth Floor, Boston, MA 02110-1335 USA
17 
18 *****************************************************************************/
19 
20 /**************************************************//**
21 @file include/buf0flu.h
22 The database buffer pool flush algorithm
23 
24 Created 11/5/1995 Heikki Tuuri
25 *******************************************************/
26 
27 #ifndef buf0flu_h
28 #define buf0flu_h
29 
30 #include "ut0byte.h"
31 #include "log0log.h"
32 #include "buf0types.h"
33 
34 /** Flag indicating if the page_cleaner is in active state. */
35 extern bool buf_page_cleaner_is_active;
36 
37 #ifdef UNIV_DEBUG
38 
39 /** Value of MySQL global variable used to disable page cleaner. */
40 extern my_bool		innodb_page_cleaner_disabled_debug;
41 
42 #endif /* UNIV_DEBUG */
43 
44 /** Event to synchronise with the flushing. */
45 extern os_event_t	buf_flush_event;
46 
47 class ut_stage_alter_t;
48 
49 /** Handled page counters for a single flush */
50 struct flush_counters_t {
51 	ulint	flushed;	/*!< number of dirty pages flushed */
52 	ulint	evicted;	/*!< number of clean pages evicted */
53 	ulint	unzip_LRU_evicted;/*!< number of uncompressed page images
poll_write( self: Pin<&mut Self>, _: &mut Context<'_>, buf: &[u8], ) -> Poll<Result<usize, io::Error>>54 				evicted */
55 };
56 
57 /********************************************************************//**
58 Remove a block from the flush list of modified blocks. */
59 void
60 buf_flush_remove(
61 /*=============*/
62 	buf_page_t*	bpage);	/*!< in: pointer to the block in question */
poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<(), io::Error>>63 /*******************************************************************//**
64 Relocates a buffer control block on the flush_list.
65 Note that it is assumed that the contents of bpage has already been
66 copied to dpage. */
67 void
68 buf_flush_relocate_on_flush_list(
69 /*=============================*/
70 	buf_page_t*	bpage,	/*!< in/out: control block being moved */
71 	buf_page_t*	dpage);	/*!< in/out: destination block */
72 /** Update the flush system data structures when a write is completed.
73 @param[in,out]	bpage	flushed page
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result74 @param[in]	dblwr	whether the doublewrite buffer was used */
75 void buf_flush_write_complete(buf_page_t* bpage, bool dblwr);
76 /** Initialize a page for writing to the tablespace.
77 @param[in]	block		buffer block; NULL if bypassing the buffer pool
78 @param[in,out]	page		page frame
79 @param[in,out]	page_zip_	compressed page, or NULL if uncompressed
80 @param[in]	newest_lsn	newest modification LSN to the page */
81 void
82 buf_flush_init_for_writing(
83 	const buf_block_t*	block,
assert_unpin()84 	byte*			page,
85 	void*			page_zip_,
86 	lsn_t			newest_lsn);
87 
88 # if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
89 /********************************************************************//**
90 Writes a flushable page asynchronously from the buffer pool to a file.
91 NOTE: buf_pool->mutex and block->mutex must be held upon entering this
92 function, and they will be released by this function after flushing.
93 This is loosely based on buf_flush_batch() and buf_flush_page().
94 @return TRUE if the page was flushed and the mutexes released */
95 ibool
96 buf_flush_page_try(
97 /*===============*/
98 	buf_pool_t*	buf_pool,	/*!< in/out: buffer pool instance */
99 	buf_block_t*	block)		/*!< in/out: buffer control 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		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
116 buf_flush_do_batch(
117 	buf_pool_t*		buf_pool,
118 	buf_flush_t		type,
119 	ulint			min_n,
120 	lsn_t			lsn_limit,
121 	flush_counters_t*	n);
122 
123 /** This utility flushes dirty blocks from the end of the flush list of all
124 buffer pool instances.
125 NOTE: The calling thread is not allowed to own any latches on pages!
126 @param[in]	min_n		wished minimum mumber of blocks flushed (it is
127 not guaranteed that the actual number is that big, though)
128 @param[in]	lsn_limit	in the case BUF_FLUSH_LIST all blocks whose
129 oldest_modification is smaller than this should be flushed (if their number
130 does not exceed min_n), otherwise ignored
131 @param[out]	n_processed	the number of pages which were processed is
132 passed back to caller. Ignored if NULL.
133 @return true if a batch was queued successfully for each buffer pool
134 instance. false if another batch of same type was already running in
135 at least one of the buffer pool instance */
136 bool
137 buf_flush_lists(
138 	ulint			min_n,
139 	lsn_t			lsn_limit,
140 	ulint*			n_processed);
141 
142 /******************************************************************//**
143 This function picks up a single page from the tail of the LRU
144 list, flushes it (if it is dirty), removes it from page_hash and LRU
145 list and puts it on the free list. It is called from user threads when
146 they are unable to find a replaceable page at the tail of the LRU
147 list i.e.: when the background LRU flushing in the page_cleaner thread
148 is not fast enough to keep pace with the workload.
149 @return true if success. */
150 bool
151 buf_flush_single_page_from_LRU(
152 /*===========================*/
153 	buf_pool_t*	buf_pool);	/*!< in/out: buffer pool instance */
154 /******************************************************************//**
155 Waits until a flush batch of the given type ends */
156 void
157 buf_flush_wait_batch_end(
158 /*=====================*/
159 	buf_pool_t*	buf_pool,	/*!< in: buffer pool instance */
160 	buf_flush_t	type);		/*!< in: BUF_FLUSH_LRU
161 					or BUF_FLUSH_LIST */
162 /**
163 Waits until a flush batch of the given lsn ends
164 @param[in]	new_oldest	target oldest_modified_lsn to wait for */
165 
166 void
167 buf_flush_wait_flushed(
168 	lsn_t		new_oldest);
169 
170 /********************************************************************//**
171 This function should be called at a mini-transaction commit, if a page was
172 modified in it. Puts the block to the list of modified blocks, if it not
173 already in it. */
174 UNIV_INLINE
175 void
176 buf_flush_note_modification(
177 /*========================*/
178 	buf_block_t*	block,		/*!< in: block which is modified */
179 	lsn_t		start_lsn,	/*!< in: start lsn of the first mtr in a
180 					set of mtr's */
181 	lsn_t		end_lsn,	/*!< in: end lsn of the last mtr in the
182 					set of mtr's */
183 	FlushObserver*	observer);	/*!< in: flush observer */
184 
185 /********************************************************************//**
186 This function should be called when recovery has modified a buffer page. */
187 UNIV_INLINE
188 void
189 buf_flush_recv_note_modification(
190 /*=============================*/
191 	buf_block_t*	block,		/*!< in: block which is modified */
192 	lsn_t		start_lsn,	/*!< in: start lsn of the first mtr in a
193 					set of mtr's */
194 	lsn_t		end_lsn);	/*!< in: end lsn of the last mtr in the
195 					set of mtr's */
196 /********************************************************************//**
197 Returns TRUE if the file page block is immediately suitable for replacement,
198 i.e., transition FILE_PAGE => NOT_USED allowed.
199 @return TRUE if can replace immediately */
200 ibool
201 buf_flush_ready_for_replace(
202 /*========================*/
203 	buf_page_t*	bpage);	/*!< in: buffer control block, must be
204 				buf_page_in_file(bpage) and in the LRU list */
205 
206 #ifdef UNIV_DEBUG
207 /** Disables page cleaner threads (coordinator and workers).
208 It's used by: SET GLOBAL innodb_page_cleaner_disabled_debug = 1 (0).
209 @param[in]	save		immediate result from check function */
210 void buf_flush_page_cleaner_disabled_debug_update(THD*,
211 						  st_mysql_sys_var*, void*,
212 						  const void* save);
213 #endif /* UNIV_DEBUG */
214 
215 /******************************************************************//**
216 page_cleaner thread tasked with flushing dirty pages from the buffer
217 pools. As of now we'll have only one coordinator of this thread.
218 @return a dummy parameter */
219 extern "C"
220 os_thread_ret_t
221 DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(
222 /*===============================================*/
223 	void*	arg);		/*!< in: a dummy parameter required by
224 				os_thread_create */
225 
226 /** Adjust thread count for page cleaner workers.
227 @param[in]	new_cnt		Number of threads to be used */
228 void
229 buf_flush_set_page_cleaner_thread_cnt(ulong new_cnt);
230 
231 /******************************************************************//**
232 Worker thread of page_cleaner.
233 @return a dummy parameter */
234 extern "C"
235 os_thread_ret_t
236 DECLARE_THREAD(buf_flush_page_cleaner_worker)(
237 /*==========================================*/
238 	void*	arg);		/*!< in: a dummy parameter required by
239 				os_thread_create */
240 /** Initialize page_cleaner. */
241 void
242 buf_flush_page_cleaner_init(void);
243 
244 /** Wait for any possible LRU flushes that are in progress to end. */
245 void
246 buf_flush_wait_LRU_batch_end(void);
247 
248 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
249 /******************************************************************//**
250 Validates the flush list.
251 @return TRUE if ok */
252 ibool
253 buf_flush_validate(
254 /*===============*/
255 	buf_pool_t*	buf_pool);
256 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
257 
258 /********************************************************************//**
259 Initialize the red-black tree to speed up insertions into the flush_list
260 during recovery process. Should be called at the start of recovery
261 process before any page has been read/written. */
262 void
263 buf_flush_init_flush_rbt(void);
264 /*==========================*/
265 
266 /********************************************************************//**
267 Frees up the red-black tree. */
268 void
269 buf_flush_free_flush_rbt(void);
270 /*==========================*/
271 
272 /********************************************************************//**
273 Writes a flushable page asynchronously from the buffer pool to a file.
274 NOTE: in simulated aio we must call
275 os_aio_simulated_wake_handler_threads after we have posted a batch of
276 writes! NOTE: buf_pool->mutex and buf_page_get_mutex(bpage) must be
277 held upon entering this function, and they will be released by this
278 function.
279 @return TRUE if page was flushed */
280 ibool
281 buf_flush_page(
282 /*===========*/
283 	buf_pool_t*	buf_pool,	/*!< in: buffer pool instance */
284 	buf_page_t*	bpage,		/*!< in: buffer control block */
285 	buf_flush_t	flush_type,	/*!< in: type of flush */
286 	bool		sync);		/*!< in: true if sync IO request */
287 /********************************************************************//**
288 Returns true if the block is modified and ready for flushing.
289 @return true if can flush immediately */
290 bool
291 buf_flush_ready_for_flush(
292 /*======================*/
293 	buf_page_t*	bpage,	/*!< in: buffer control block, must be
294 				buf_page_in_file(bpage) */
295 	buf_flush_t	flush_type)/*!< in: type of flush */
296 	MY_ATTRIBUTE((warn_unused_result));
297 
298 /******************************************************************//**
299 Check if there are any dirty pages that belong to a space id in the flush
300 list in a particular buffer pool.
301 @return number of dirty pages present in a single buffer pool */
302 ulint
303 buf_pool_get_dirty_pages_count(
304 /*===========================*/
305 	buf_pool_t*	buf_pool,	/*!< in: buffer pool */
306 	ulint		id,		/*!< in: space id to check */
307 	FlushObserver*	observer);	/*!< in: flush observer to check */
308 
309 /*******************************************************************//**
310 Synchronously flush dirty blocks from the end of the flush list of all buffer
311 pool instances.
312 NOTE: The calling thread is not allowed to own any latches on pages! */
313 void
314 buf_flush_sync_all_buf_pools(void);
315 /*==============================*/
316 
317 /** Request IO burst and wake page_cleaner up.
318 @param[in]	lsn_limit	upper limit of LSN to be flushed */
319 void
320 buf_flush_request_force(
321 	lsn_t	lsn_limit);
322 
323 /** We use FlushObserver to track flushing of non-redo logged pages in bulk
324 create index(BtrBulk.cc).Since we disable redo logging during a index build,
325 we need to make sure that all dirty pages modifed by the index build are
326 flushed to disk before any redo logged operations go to the index. */
327 
328 class FlushObserver {
329 public:
330 	/** Constructor
331 	@param[in,out]	space		tablespace
332 	@param[in]	trx		trx instance
333 	@param[in]	stage		performance schema accounting object,
334 	used by ALTER TABLE. It is passed to log_preflush_pool_modified_pages()
335 	for accounting. */
336 	FlushObserver(fil_space_t* space, trx_t* trx, ut_stage_alter_t* stage);
337 
338 	/** Deconstructor */
339 	~FlushObserver();
340 
341 	/** Check pages have been flushed and removed from the flush list
342 	in a buffer pool instance.
343 	@param[in]	instance_no	buffer pool instance no
344 	@return true if the pages were removed from the flush list */
345 	bool is_complete(ulint	instance_no)
346 	{
347 		return(m_flushed->at(instance_no) == m_removed->at(instance_no)
348 		       || m_interrupted);
349 	}
350 
351 	/** @return whether to flush only some pages of the tablespace */
352 	bool is_partial_flush() const { return m_stage != NULL; }
353 
354 	/** @return whether the operation was interrupted */
355 	bool is_interrupted() const { return m_interrupted; }
356 
357 	/** Interrupt observer not to wait. */
358 	void interrupted()
359 	{
360 		m_interrupted = true;
361 	}
362 
363 	/** Check whether the operation has been interrupted */
364 	void check_interrupted();
365 
366 	/** Flush dirty pages. */
367 	void flush();
368 	/** Notify observer of flushing a page
369 	@param[in]	buf_pool	buffer pool instance
370 	@param[in]	bpage		buffer page to flush */
371 	void notify_flush(
372 		buf_pool_t*	buf_pool,
373 		buf_page_t*	bpage);
374 
375 	/** Notify observer of removing a page from flush list
376 	@param[in]	buf_pool	buffer pool instance
377 	@param[in]	bpage		buffer page flushed */
378 	void notify_remove(
379 		buf_pool_t*	buf_pool,
380 		buf_page_t*	bpage);
381 private:
382 	/** Tablespace */
383 	fil_space_t*		m_space;
384 
385 	/** Trx instance */
386 	const trx_t* const	m_trx;
387 
388 	/** Performance schema accounting object, used by ALTER TABLE.
389 	If not NULL, then stage->begin_phase_flush() will be called initially,
390 	specifying the number of pages to be attempted to be flushed and
391 	subsequently, stage->inc() will be called for each page we attempt to
392 	flush. */
393 	ut_stage_alter_t*	m_stage;
394 
395 	/* Flush request sent */
396 	std::vector<ulint>*	m_flushed;
397 
398 	/* Flush request finished */
399 	std::vector<ulint>*	m_removed;
400 
401 	/* True if the operation was interrupted. */
402 	bool			m_interrupted;
403 };
404 
405 #include "buf0flu.inl"
406 
407 #endif
408