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
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 */
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
74 @param[in]	dblwr	whether the doublewrite buffer was used */
75 void buf_flush_write_complete(buf_page_t* bpage, bool dblwr);
76 
77 /** Assign the full crc32 checksum for non-compressed page.
78 @param[in,out]	page	page to be updated */
79 void buf_flush_assign_full_crc32_checksum(byte* page);
80 
81 /** Initialize a page for writing to the tablespace.
82 @param[in]	block			buffer block; NULL if bypassing the buffer pool
83 @param[in,out]	page			page frame
84 @param[in,out]	page_zip_		compressed page, or NULL if uncompressed
85 @param[in]	newest_lsn		newest modification LSN to the page
86 @param[in]	use_full_checksum	whether tablespace uses full checksum */
87 void
88 buf_flush_init_for_writing(
89 	const buf_block_t*	block,
90 	byte*			page,
91 	void*			page_zip_,
92 	lsn_t			newest_lsn,
93 	bool			use_full_checksum);
94 
95 # if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
96 /********************************************************************//**
97 Writes a flushable page asynchronously from the buffer pool to a file.
98 NOTE: buf_pool->mutex and block->mutex must be held upon entering this
99 function, and they will be released by this function after flushing.
100 This is loosely based on buf_flush_batch() and buf_flush_page().
101 @return TRUE if the page was flushed and the mutexes released */
102 ibool
103 buf_flush_page_try(
104 /*===============*/
105 	buf_pool_t*	buf_pool,	/*!< in/out: buffer pool instance */
106 	buf_block_t*	block)		/*!< in/out: buffer control block */
107 	MY_ATTRIBUTE((warn_unused_result));
108 # endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
109 /** Do flushing batch of a given type.
110 NOTE: The calling thread is not allowed to own any latches on pages!
111 @param[in,out]	buf_pool	buffer pool instance
112 @param[in]	type		flush type
113 @param[in]	min_n		wished minimum mumber of blocks flushed
114 (it is not guaranteed that the actual number is that big, though)
115 @param[in]	lsn_limit	in the case BUF_FLUSH_LIST all blocks whose
116 oldest_modification is smaller than this should be flushed (if their number
117 does not exceed min_n), otherwise ignored
118 @param[out]	n		the number of pages which were processed is
119 passed back to caller. Ignored if NULL
120 @retval true	if a batch was queued successfully.
121 @retval false	if another batch of same type was already running. */
122 bool
123 buf_flush_do_batch(
124 	buf_pool_t*		buf_pool,
125 	buf_flush_t		type,
126 	ulint			min_n,
127 	lsn_t			lsn_limit,
128 	flush_counters_t*	n);
129 
130 /** This utility flushes dirty blocks from the end of the flush list of all
131 buffer pool instances.
132 NOTE: The calling thread is not allowed to own any latches on pages!
133 @param[in]	min_n		wished minimum mumber of blocks flushed (it is
134 not guaranteed that the actual number is that big, though)
135 @param[in]	lsn_limit	in the case BUF_FLUSH_LIST all blocks whose
136 oldest_modification is smaller than this should be flushed (if their number
137 does not exceed min_n), otherwise ignored
138 @param[out]	n_processed	the number of pages which were processed is
139 passed back to caller. Ignored if NULL.
140 @return true if a batch was queued successfully for each buffer pool
141 instance. false if another batch of same type was already running in
142 at least one of the buffer pool instance */
143 bool
144 buf_flush_lists(
145 	ulint			min_n,
146 	lsn_t			lsn_limit,
147 	ulint*			n_processed);
148 
149 /******************************************************************//**
150 This function picks up a single page from the tail of the LRU
151 list, flushes it (if it is dirty), removes it from page_hash and LRU
152 list and puts it on the free list. It is called from user threads when
153 they are unable to find a replaceable page at the tail of the LRU
154 list i.e.: when the background LRU flushing in the page_cleaner thread
155 is not fast enough to keep pace with the workload.
156 @return true if success. */
157 bool
158 buf_flush_single_page_from_LRU(
159 /*===========================*/
160 	buf_pool_t*	buf_pool);	/*!< in/out: buffer pool instance */
161 /******************************************************************//**
162 Waits until a flush batch of the given type ends */
163 void
164 buf_flush_wait_batch_end(
165 /*=====================*/
166 	buf_pool_t*	buf_pool,	/*!< in: buffer pool instance */
167 	buf_flush_t	type);		/*!< in: BUF_FLUSH_LRU
168 					or BUF_FLUSH_LIST */
169 /**
170 Waits until a flush batch of the given lsn ends
171 @param[in]	new_oldest	target oldest_modified_lsn to wait for */
172 
173 void
174 buf_flush_wait_flushed(
175 	lsn_t		new_oldest);
176 
177 /********************************************************************//**
178 This function should be called at a mini-transaction commit, if a page was
179 modified in it. Puts the block to the list of modified blocks, if it not
180 already in it. */
181 UNIV_INLINE
182 void
183 buf_flush_note_modification(
184 /*========================*/
185 	buf_block_t*	block,		/*!< in: block which is modified */
186 	lsn_t		start_lsn,	/*!< in: start lsn of the first mtr in a
187 					set of mtr's */
188 	lsn_t		end_lsn,	/*!< in: end lsn of the last mtr in the
189 					set of mtr's */
190 	FlushObserver*	observer);	/*!< in: flush observer */
191 /********************************************************************//**
192 Returns TRUE if the file page block is immediately suitable for replacement,
193 i.e., transition FILE_PAGE => NOT_USED allowed.
194 @return TRUE if can replace immediately */
195 ibool
196 buf_flush_ready_for_replace(
197 /*========================*/
198 	buf_page_t*	bpage);	/*!< in: buffer control block, must be
199 				buf_page_in_file(bpage) and in the LRU list */
200 
201 #ifdef UNIV_DEBUG
202 /** Disables page cleaner threads (coordinator and workers).
203 It's used by: SET GLOBAL innodb_page_cleaner_disabled_debug = 1 (0).
204 @param[in]	save		immediate result from check function */
205 void buf_flush_page_cleaner_disabled_debug_update(THD*,
206 						  st_mysql_sys_var*, void*,
207 						  const void* save);
208 #endif /* UNIV_DEBUG */
209 
210 /******************************************************************//**
211 page_cleaner thread tasked with flushing dirty pages from the buffer
212 pools. As of now we'll have only one coordinator of this thread.
213 @return a dummy parameter */
214 extern "C"
215 os_thread_ret_t
216 DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(
217 /*===============================================*/
218 	void*	arg);		/*!< in: a dummy parameter required by
219 				os_thread_create */
220 
221 /** Adjust thread count for page cleaner workers.
222 @param[in]	new_cnt		Number of threads to be used */
223 void
224 buf_flush_set_page_cleaner_thread_cnt(ulong new_cnt);
225 
226 /******************************************************************//**
227 Worker thread of page_cleaner.
228 @return a dummy parameter */
229 extern "C"
230 os_thread_ret_t
231 DECLARE_THREAD(buf_flush_page_cleaner_worker)(
232 /*==========================================*/
233 	void*	arg);		/*!< in: a dummy parameter required by
234 				os_thread_create */
235 /** Initialize page_cleaner. */
236 void
237 buf_flush_page_cleaner_init(void);
238 
239 /** Wait for any possible LRU flushes that are in progress to end. */
240 void
241 buf_flush_wait_LRU_batch_end(void);
242 
243 #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
244 /******************************************************************//**
245 Validates the flush list.
246 @return TRUE if ok */
247 ibool
248 buf_flush_validate(
249 /*===============*/
250 	buf_pool_t*	buf_pool);
251 #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
252 
253 /********************************************************************//**
254 Initialize the red-black tree to speed up insertions into the flush_list
255 during recovery process. Should be called at the start of recovery
256 process before any page has been read/written. */
257 void
258 buf_flush_init_flush_rbt(void);
259 /*==========================*/
260 
261 /********************************************************************//**
262 Frees up the red-black tree. */
263 void
264 buf_flush_free_flush_rbt(void);
265 /*==========================*/
266 
267 /********************************************************************//**
268 Writes a flushable page asynchronously from the buffer pool to a file.
269 NOTE: in simulated aio we must call
270 os_aio_simulated_wake_handler_threads after we have posted a batch of
271 writes! NOTE: buf_pool->mutex and buf_page_get_mutex(bpage) must be
272 held upon entering this function, and they will be released by this
273 function.
274 @return TRUE if page was flushed */
275 ibool
276 buf_flush_page(
277 /*===========*/
278 	buf_pool_t*	buf_pool,	/*!< in: buffer pool instance */
279 	buf_page_t*	bpage,		/*!< in: buffer control block */
280 	buf_flush_t	flush_type,	/*!< in: type of flush */
281 	bool		sync);		/*!< in: true if sync IO request */
282 /********************************************************************//**
283 Returns true if the block is modified and ready for flushing.
284 @return true if can flush immediately */
285 bool
286 buf_flush_ready_for_flush(
287 /*======================*/
288 	buf_page_t*	bpage,	/*!< in: buffer control block, must be
289 				buf_page_in_file(bpage) */
290 	buf_flush_t	flush_type)/*!< in: type of flush */
291 	MY_ATTRIBUTE((warn_unused_result));
292 
293 /******************************************************************//**
294 Check if there are any dirty pages that belong to a space id in the flush
295 list in a particular buffer pool.
296 @return number of dirty pages present in a single buffer pool */
297 ulint
298 buf_pool_get_dirty_pages_count(
299 /*===========================*/
300 	buf_pool_t*	buf_pool,	/*!< in: buffer pool */
301 	ulint		id,		/*!< in: space id to check */
302 	FlushObserver*	observer);	/*!< in: flush observer to check */
303 
304 /*******************************************************************//**
305 Synchronously flush dirty blocks from the end of the flush list of all buffer
306 pool instances.
307 NOTE: The calling thread is not allowed to own any latches on pages! */
308 void
309 buf_flush_sync_all_buf_pools(void);
310 /*==============================*/
311 
312 /** Request IO burst and wake page_cleaner up.
313 @param[in]	lsn_limit	upper limit of LSN to be flushed */
314 void
315 buf_flush_request_force(
316 	lsn_t	lsn_limit);
317 
318 /** We use FlushObserver to track flushing of non-redo logged pages in bulk
319 create index(BtrBulk.cc).Since we disable redo logging during a index build,
320 we need to make sure that all dirty pages modifed by the index build are
321 flushed to disk before any redo logged operations go to the index. */
322 
323 class FlushObserver {
324 public:
325 	/** Constructor
326 	@param[in,out]	space		tablespace
327 	@param[in]	trx		trx instance
328 	@param[in]	stage		performance schema accounting object,
329 	used by ALTER TABLE. It is passed to log_preflush_pool_modified_pages()
330 	for accounting. */
331 	FlushObserver(fil_space_t* space, trx_t* trx, ut_stage_alter_t* stage);
332 
333 	/** Deconstructor */
334 	~FlushObserver();
335 
336 	/** Check pages have been flushed and removed from the flush list
337 	in a buffer pool instance.
338 	@param[in]	instance_no	buffer pool instance no
339 	@return true if the pages were removed from the flush list */
is_complete(ulint instance_no)340 	bool is_complete(ulint	instance_no)
341 	{
342 		return(m_flushed->at(instance_no) == m_removed->at(instance_no)
343 		       || m_interrupted);
344 	}
345 
346 	/** @return whether to flush only some pages of the tablespace */
is_partial_flush()347 	bool is_partial_flush() const { return m_stage != NULL; }
348 
349 	/** @return whether the operation was interrupted */
is_interrupted()350 	bool is_interrupted() const { return m_interrupted; }
351 
352 	/** Interrupt observer not to wait. */
interrupted()353 	void interrupted()
354 	{
355 		m_interrupted = true;
356 	}
357 
358 	/** Check whether the operation has been interrupted */
359 	void check_interrupted();
360 
361 	/** Flush dirty pages. */
362 	void flush();
363 	/** Notify observer of flushing a page
364 	@param[in]	buf_pool	buffer pool instance
365 	@param[in]	bpage		buffer page to flush */
366 	void notify_flush(
367 		buf_pool_t*	buf_pool,
368 		buf_page_t*	bpage);
369 
370 	/** Notify observer of removing a page from flush list
371 	@param[in]	buf_pool	buffer pool instance
372 	@param[in]	bpage		buffer page flushed */
373 	void notify_remove(
374 		buf_pool_t*	buf_pool,
375 		buf_page_t*	bpage);
376 private:
377 	/** Tablespace */
378 	fil_space_t*		m_space;
379 
380 	/** Trx instance */
381 	const trx_t* const	m_trx;
382 
383 	/** Performance schema accounting object, used by ALTER TABLE.
384 	If not NULL, then stage->begin_phase_flush() will be called initially,
385 	specifying the number of pages to be attempted to be flushed and
386 	subsequently, stage->inc() will be called for each page we attempt to
387 	flush. */
388 	ut_stage_alter_t*	m_stage;
389 
390 	/* Flush request sent */
391 	std::vector<ulint>*	m_flushed;
392 
393 	/* Flush request finished */
394 	std::vector<ulint>*	m_removed;
395 
396 	/* True if the operation was interrupted. */
397 	bool			m_interrupted;
398 };
399 
400 #include "buf0flu.inl"
401 
402 #endif
403