MySQL 26.7.0
Source Code Documentation
fil0pages_persistence_interface.h
Go to the documentation of this file.
1/* Copyright (c) 2022, 2026, Oracle and/or its affiliates.
2
3This program is free software; you can redistribute it and/or modify it under
4the terms of the GNU General Public License, version 2.0, as published by the
5Free Software Foundation.
6
7This program is designed to work with certain software (including
8but not limited to OpenSSL) that is licensed under separate terms,
9as designated in a particular file or component or in included license
10documentation. The authors of MySQL hereby grant you an additional
11permission to link the program and your derivative works with the
12separately licensed software that they have either included with
13the program or referenced in the documentation.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
18for more details.
19
20You should have received a copy of the GNU General Public License along with
21this program; if not, write to the Free Software Foundation, Inc.,
2251 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23*/
24
25#pragma once
26
27#include "fil0tablespaces_nodes_interface.h" /* Tablespaces_nodes_interface::Tablespace_id */
28#include "log0common.h" /* ib::redo::Lsn */
29#include "ut0expected.h" /* ut::Expected */
30#include "ut0function_reference.h" /* ut::Function_reference */
31#include "ut0new.h" /* ut::unique_pt */
32
33class Flush_observer;
34struct buf_block_t;
35
36namespace ib {
37class Monitoring_interface;
38class Sys_var_handler_interface;
39} // namespace ib
40
41namespace ib::fil {
42
43/** Interface for handling operations related to page persistence */
45 public:
46 /** Type used for numbering the pages in the tablespace. */
48
49 /** Type used for giving the tablespaces unique number. */
52
53 enum class Status { SUCCESS = 0, IO_ERROR };
54
55 /** @name Lifecycle methods
56
57 In InnoDB Persistence of Pages involves several modules and operations which
58 are started gradually during server boot, which is reflected in this API.
59
60 The page cleaner threads - the buf_flush_page_coordinator_thread() and several
61 instances of buf_flush_page_cleaner_thread() spawned by it - are responsible
62 for writing dirty pages from BP to tablespaces. They do this already during
63 recovery, as recovery is applying changes from redo log to pages in BP. They
64 continue to do so during runtime, reacting to changes made by mtrs. The
65 "speed" at which they do so, and the source of pages to flush (flush lists or
66 LRU) may change over time but their main goal is to make sure changes which we
67 redo log are also persisted to tablespaces storage.
68 They get started in init().
69 They get stopped implicitly by changing the srv_shutdown_state to
70 SRV_SHUTDOWN_FLUSH_PHASE in srv_shutdown_page_cleaners() and is considered
71 done once there are no active page cleaners.
72
73 @note It is page cleaners who do the heavy work of actually writing pages, and
74 this way making sure the state of persisted pages marches forward.
75 However, it is not their job to "make a checkpoint" (store the minimum needed
76 lsn value in durable place) nor to "bump the Checkpoint LSN" (compute and
77 announce to other modules of the code the minimum needed lsn value). They
78 merely afford doing so, by ensuring that all changes up to a given LSN are
79 already persisted to tablespaces, so that a higher value of LSN is now
80 "available for checkpoint", and thus Checkpoint LSN can be bumped and its
81 value can be stored in a place which would survive a crash - but this is a job
82 of log checkpointer thread.
83
84 The log checkpointer - the Log_checkpointing::do_work thread is monitoring the
85 lsn available for checkpoint reported by page cleaners and if it decides it is
86 a good moment to persist that value as Checkpoint LSN, then it does so, and
87 additionally calls
88 ib::redo::handler->do_not_need_smaller_than(new_checkpoint_lsn), to inform
89 Redo log handler that descriptions of changes below this lsn are no longer
90 needed. We call this operation "checkpointing", or "making a checkpoint". How
91 often to make it is determined by configuration and stage of bootstrap and
92 explicit requests to do so from code. It doesn't do so during recovery, to not
93 truncate a redo log prefix containing Persistent Table Metadata which it might
94 need to reread in case we crash again during recovery. It's started after
95 recover_tables() has stored PTM info to B-tree, using enable_checkpointing().
96 From this moment the Checkpoint LSN value can be bumped and stored.
97 It's further encouraged by enable_periodical_checkpoints() to occur on timely
98 fashion even if nobody requested it.
99 The disable_checkpointing() stops the checkpointing (and log checkpointer).
100
101 In order to properly track the lsn available for checkpoint, InnoDB uses a
102 Link_buf data structure to know what ranges of changes got already reported
103 by mtr_has_dirtied_pages(). However this data structure needs to be:
104 - constructed in init(),
105 - informed from what value to start in assume_checkpoint_lsn(lsn) or decided
106 automatically at the end of recover_pages(..),
107 - and destructed in deinit().
108
109 The class can also have a constructor and destructor, however be aware that
110 the destructor might get called during abort() and thus it might be difficult
111 to execute any code which depends on already destructed infrastructure like
112 performance schema (used by mutexes, events etc.). */
113 /** @{ */
114
115 virtual ~Pages_persistence_interface() = default;
116
117 /** Redo a create tablespace storage operation for a tablespace.
118 This operation is done when REDOs are replayed and must be successful.
119 @param[in] space_id Tablespace id
120 @param[in] flags Tablespace flags
121 @param[in] path path of tablespace storage */
124 const char *path) = 0;
125
126 /** Redo a delete tablespace storage operation for a tablespace.
127 This operation is done when REDOs are replayed and must be successful.
128 @param[in] space_id Tablespace id
129 @param[in] path path of tablespace storage */
131 const char *path) = 0;
132
133 /** Redo a rename operation for a tablespace.
134 This operation is done when REDOs are replayed and must be successful.
135 @param[in] space_id Tablespace id
136 @param[in] old_path current path tablespace storage
137 @param[in] new_path target path of tablespace storage */
139 const char *old_path,
140 const char *new_path) = 0;
141
142 /** Allocate and construct helper data structures and start persisting changes
143 to pages, but do not start persisting the progress of that operation: the
144 values reported by get_checkpoint_lsn() should not change, and
145 ib::redo::handler->do_not_need_smaller_than(lsn) should not be called.
146 That is: page cleaners can start now, but log check pointer can not.
147 @return IO_ERROR due to one of plenty possible IO errors, SUCCESS otherwise */
148 [[nodiscard]] virtual Status init() = 0;
149
150 /** The caller asks the implementation to assume that redo log below
151 min_needed_lsn is not available and is not needed anymore because pages have
152 all changes below this lsn already persisted. Also, the next change to come
153 will be min_needed_lsn. In other words the redo log is logically empty:
154 all changes were already persisted to pages.
155 That is, the checkpoint lsn is at min_needed_lsn and no dirty page will be
156 added with a lower lsn in future.
157 This is currently used only when initializing a new instance.
158 @param[in] min_needed_lsn
159 the current snapshot of the database (its tablespaces),
160 the start and the end of the redo log,
161 the only available version of it
162 @retval SUCCESS
163 everything went fine: the min_needed_lsn value was stored in
164 Redo log handler's metadata, and get_checkpoint_lsn() would
165 return min_needed_lsn if called
166 @retval IO_ERROR
167 could not persist the value of min needed lsn (make a checkpoint)
168 */
169 [[nodiscard]] virtual Status assume_checkpoint_lsn(Lsn min_needed_lsn) = 0;
170
171 /** From now on, the implementation is permitted to bump the min needed lsn
172 value reported and persisted - that is, not only can it persist changes to
173 pages but moreover it can persist the state of progress of this operation.
174 That is, the log checkpointer can be started now. */
175 virtual void enable_checkpointing() = 0;
176
177 /** From now on, not only advancing the min needed lsn is permitted, but also
178 encouraged. Before a call to this function it should only be done if really
179 needed for correctness, but avoided otherwise to make the behaviour more
180 deterministic. From now on, unsolicited, periodical advancements are no
181 longer a problem and can actually help in reclaiming redo log space.
182 That is, the log checkpointer can start periodical checkpoints.*/
184
185 /** From now on, the implementation is no longer permitted to bump the min
186 needed lsn.
187 That is, the log checkpointer thread should be stopped now. */
188 virtual void disable_checkpointing() = 0;
189
190 /** Deinitialize whatever was initialized in init(). This is called when
191 shutting down in a planned way (as opposed to the destructor which might be
192 called indirectly from mysql_exit on abort, in which case the order of
193 destruction can be problematic - for example PFS or some other piece of
194 infrastructure might be no longer available) */
195 virtual void deinit() = 0;
196
197 /** @} */
198
199 /** @name Handling pages dirtied by mtrs */
200 /** @{ */
201
202 /** The caller informs that it is now committing an mtr which has dirtied
203 some pages. The pages are still latched in BP, but it will not dirty any more
204 pages, and the range of lsns is already assigned to it (unless the redo
205 logging is not enabled for this mtr, i.e. MTR_LOG_SHORT_INSERTS,
206 MTR_LOG_NO_REDO or MTR_LOG_NONE was used). This is a good moment to add
207 dirtied pages to flush lists.
208 @param[in] start_lsn
209 the start lsn of the committing mtr. It is 0 iff this mtr
210 is not redo logged.
211 @param[in] end_lsn
212 the end lsn of the committing mtr. It is 0 iff this mtr
213 is not redo logged.
214 @param[in] observer
215 the Flush observer (if any) attached to this mtr
216 @param[in] iterate_over_dirty_pages
217 a function that can be used to iterate over all pages
218 dirtied committing mtr by passing a visitor callback to it.
219 The visitor will be called AT LEAST once for each dirtied
220 page.
221 */
223 Lsn start_lsn, Lsn end_lsn, ::Flush_observer *observer,
225 iterate_over_dirty_pages) = 0;
226
227 /** A callback that is called from buf_flush_note_oldest_modification() once
228 for each page that became dirty, assuming buf_flush_note_oldest_modification()
229 is called at all from mtr_has_dirtied_pages(), for example by calling
230 buf_flush_note_modification() from visitor passed to iterate_over_dirty_pages.
231 TODO: is it really needed if we have mtr_has_dirtied_pages() ?
232 @param[in] buf_block Block for Page that became dirty.
233 */
234 virtual void page_became_dirty(buf_block_t *buf_block) = 0;
235
236 /** Makes sure that for a specified tablespace all changes to pages are
237 persisted. This requires all pages from the Buffer Pool (for the
238 specified tablespace) that were dirty before this call, to be made clean. This
239 will remove such pages from the flush_list, but not from the Buffer Pool
240 itself (and thus will not remove from LRU list). In case the specified
241 transaction is interrupted before or during the call, whatever pages were not
242 yet processed, will not be touched and thus will remain in both lists.
243 @param[in] space_id
244 The id of the tablespace to persist its pages.
245 @param[in] trx
246 Transaction, if any, to monitor for interrupted operation.
247 */
248 virtual void persist_tablespace(Tablespace_id space_id, const trx_t *trx) = 0;
249
250 /** Makes sure that all changes to pages that are observed by a specified
251 flush observer are persisted. This requires all such pages from the Buffer
252 Pool that were dirty before this call, to be made clean. This will remove such
253 pages from the flush_list, but not from the Buffer Pool itself (and thus will
254 not remove from LRU list). In case the transaction that is linked to the
255 specified FlushObserver instance is interrupted before or during the call, all
256 pages that were not flushed before noticing the interruption, will be removed
257 from the flush_list, causing them to be considered clean. They will not be
258 ever written back even when evicted from the LRU. This means that the changes
259 observed by the FlushObserver must not be redologged, and any future
260 modifications of this page must start from initializing it before use.
261 @param[in] observer
262 The Flush observer used to monitor the flushing process.
263 */
264 virtual void persist_tablespaces(::Flush_observer *observer) = 0;
265
266 /** @} */
267
268 /** @name Handling recovery of changes to pages after a crash */
269 /** @{ */
270
271 /** Run recovery of all tablespaces assuming they already contain all the
272 changes at least up to the provided clean_shutdown_lsn.
273 Note that this is *not* the value of min needed lsn which the persistence
274 implementation keeps track of more precisely by itself, nor even the (perhaps
275 lower) value stored when making a checkpoint via store_metadata(0,..) - it is
276 just the last value InnoDB was aware of at last clean shutdown obtained via
277 get_checkpoint_lsn() and stored in system tablespace's header.
278 The init() method must be called before attempting recover_pages(..).
279 If CLONE is supported, then it should call:
280 - arch_init(),
281 - Arch_page_sys::post_recovery_init()
282 as well.
283 @param[in,out] clean_shutdown_lsn
284 The lsn at the last clean shutdown the InnoDB knows
285 about. This method will set it to the recovered lsn.
286 @retval List of tablespaces IDs found for all discovered tablespaces
287 @retval IO_ERROR if could not perform recovery due to one of plenty possible
288 IO errors */
289 [[nodiscard]] virtual ut::Expected<
290 std::vector<Tablespaces_nodes_interface::Tablespace_id>, Status>
291 recover_pages(Lsn &clean_shutdown_lsn) = 0;
292
293 /** Run recovery of tables (in particular: mysql.innodb_dynamic_metadata)
294 based on information gathered during recover_pages().
295 Used to update PTM's B-tree using the information from redo log.
296 TODO: recover_tables() does not really belong to pages persistence, as tables
297 are a high-level concept, and recovering them is basically running SQL on top
298 of already recovered B-tree. However, this is how InnoDB currently handles PTM
299 - the redo log contains logical records which are interpreted as requests to
300 REPLACE INTO mysql.innodb_dynamic_metadata. Therefore recovery is two-stage:
301 first we recover_pages() to get physically consistent B-tree, then we apply
302 collected PTM changes extracted from those records. Once we implement WL#15550
303 we will no longer produce this kind of redo log records. If we additionally
304 assume that upgrade will require a clean shutdown then the redo log will no
305 longer contain such PTM redo log records, and we will no longer have to handle
306 them and will be able to remove this method. */
307 [[nodiscard]] virtual Status recover_tables() = 0;
308
309 /** @} */
310
311 /** @name Handling evictions of pages from buffer pool */
312 /** @{ */
313
314 /** A callback that is called once the page is freed from the BufferPool. The
315 page is already removed from the Page Hash table, but the mutex that guards
316 the page object and latch protecting the Page Hash table, are still held, so
317 this page will not be read in again while this method is executing.
318
319 @param[in] space_id
320 The id of the tablespace containing the evicted page
321 @param[in] page_no
322 Zero-based number of the evicted page within its tablespace
323 @param[in] modification_lsn
324 The highest modification LSN of the page that is being
325 evicted - that is there are no modifications to this page
326 in the range [modification_lsn, peek_first_unassigned_lsn),
327 as otherwise the page would be dirty or latched and could
328 not be evicted. In other words, if you want to bring this
329 page back to BP in the same state, you need to ensure it
330 is recovered at least up to modification_lsn. */
332 Page_number page_no,
333 Lsn modification_lsn) = 0;
334 /** @} */
335
336 /** @name Handling checkpoints
337 What is the Checkpoint LSN? The oldest lsn position in the redo log that this
338 implementation still needs. One reason it might need the redo log is to ensure
339 that database state is durable - that is, after a crash, it could reconstruct
340 the pages in the latest version even if redo log below that lsn is lost.
341 We define Checkpoint LSN to be whatever get_checkpoint_lsn() returns, which in
342 general can be a value smaller than the real answer to the abstract question
343 "what is the smallest needed lsn?" - for example, the page cleaners could have
344 already persisted newer changes to tablespaces, but did not yet announce that
345 higher lsn is available for checkpoint, or log checkpointer has not yet
346 noticed that, or haven't yet got chance to persist this higher value.
347 Note that erring on this side is safe, as having too much redo log is not a
348 correctness problem.
349 */
350 /** @{ */
351
352 /** Returns the checkpoint lsn.
353 This function should be monotone in time.
354 The returned value itself should be crash-resistant, that is, after the crash
355 the implementation should return get_checkpoint_lsn() value at least as
356 large as returned now.
357 @return the oldest lsn in the redo log still needed by this implementation of
358 pages persistence
359 */
360 [[nodiscard]] virtual Lsn get_checkpoint_lsn() const = 0;
361
362 /** The caller request the implementation to ensure that when it returns, it
363 no longer needs the redo log generated so far, i.e. the value returned by
364 subsequent calls to get_checkpoint_lsn() must be at least the value of
365 ib::redo::handler->peek_first_unassigned_lsn() would have returned before the
366 call to request_sharp_checkpoint(). This method is used from:
367 - various debug hooks
368 - places which want to ensure redo log is logically empty because:
369 - it's MEB or other "archival" situation where we need a clear start of log
370 - it is a slow or normal shutdown
371 - after we did some non-redo-logged changes to tablespaces
372 - we've imported a new tablespace
373 - we've initialized legacy double-write pages and want them written to disc,
374 and would not like to have to "recover" changes to them
375 - we've initialized new undo log rsegs - TODO: I don't understand this part
376 */
377 virtual void request_sharp_checkpoint() = 0;
378 /** @} */
379
380 /** @name Handling of sys vars */
381 /** @{ */
382
383 /** Returns an object responsible for handling updates of dynamic sys-vars
384 related to pages persistence, such as:
385 - innodb_log_checkpoint_fuzzy_now
386 - innodb_checkpoint_disabled
387 */
388 [[nodiscard]] virtual ib::Sys_var_handler_interface &config_handler() = 0;
389
390 /** @} */
391
392 /** @name Handling of INFORMATION_SCHEMA.INNODB_METRICS */
393 /** @{ */
394
395 /** Returns an object responsible for reporting values of monitors related to
396 pages persistence, such as:
397 - MONITOR_OVLD_LSN_BUF_DIRTY_PAGES_ADDED
398 - MONITOR_OVLD_BUF_OLDEST_LSN_APPROX
399 - MONITOR_OVLD_BUF_OLDEST_LSN_LWM
400 - MONITOR_OVLD_MAX_AGE_ASYNC
401 - MONITOR_OVLD_MAX_AGE_SYNC
402 @return The instance to use to obtain values of relevant monitors */
403 [[nodiscard]] virtual ib::Monitoring_interface &get_monitoring() = 0;
404
405 /** @} */
406};
407
408/** Sets the implementation of the Pages_persistence_interface. It can be called
409only once, that is, once set, it is impossible to set other implementation.
410@param[in] new_persistence New implementation to use. */
413
414} /* namespace ib::fil */
415
416/** The implementation of persistence for the pages stored in tablespaces'
417nodes' storage. */
We use Flush_observer to track flushing of non-redo logged pages in bulk create index(btr0load....
Definition: buf0flu.h:283
Interface for repoting values of some INFORMATION_SCHEMA.INNODB_METRICS.
Definition: srv0monitoring_interface.h:30
Definition: ha0sys_var_handler_interface.h:36
Interface for handling operations related to page persistence.
Definition: fil0pages_persistence_interface.h:44
virtual Lsn get_checkpoint_lsn() const =0
Returns the checkpoint lsn.
virtual Status recover_tables()=0
Run recovery of tables (in particular: mysql.innodb_dynamic_metadata) based on information gathered d...
virtual void enable_periodical_checkpoints()=0
From now on, not only advancing the min needed lsn is permitted, but also encouraged.
virtual ib::Sys_var_handler_interface & config_handler()=0
Returns an object responsible for handling updates of dynamic sys-vars related to pages persistence,...
ib::redo::Lsn Lsn
Definition: fil0pages_persistence_interface.h:51
virtual void persist_tablespace(Tablespace_id space_id, const trx_t *trx)=0
Makes sure that for a specified tablespace all changes to pages are persisted.
virtual void persist_tablespaces(::Flush_observer *observer)=0
Makes sure that all changes to pages that are observed by a specified flush observer are persisted.
virtual void disable_checkpointing()=0
From now on, the implementation is no longer permitted to bump the min needed lsn.
virtual void enable_checkpointing()=0
From now on, the implementation is permitted to bump the min needed lsn value reported and persisted ...
virtual ut::Expected< std::vector< Tablespaces_nodes_interface::Tablespace_id >, Status > recover_pages(Lsn &clean_shutdown_lsn)=0
Run recovery of all tablespaces assuming they already contain all the changes at least up to the prov...
virtual Status init()=0
Allocate and construct helper data structures and start persisting changes to pages,...
Tablespace_node_handle_interface::Page_number Page_number
Type used for numbering the pages in the tablespace.
Definition: fil0pages_persistence_interface.h:47
virtual void mtr_has_dirtied_pages(Lsn start_lsn, Lsn end_lsn, ::Flush_observer *observer, ut::Function_reference< void(ut::Function_reference< void(buf_block_t *)>)> iterate_over_dirty_pages)=0
The caller informs that it is now committing an mtr which has dirtied some pages.
virtual void redo_rename_tablespace(Tablespace_id space_id, const char *old_path, const char *new_path)=0
Redo a rename operation for a tablespace.
virtual void page_is_to_be_evicted(Tablespace_id space_id, Page_number page_no, Lsn modification_lsn)=0
A callback that is called once the page is freed from the BufferPool.
virtual void redo_create_tablespace(Tablespaces_nodes_interface::Tablespace_id space_id, uint32_t flags, const char *path)=0
Redo a create tablespace storage operation for a tablespace.
Tablespaces_nodes_interface::Tablespace_id Tablespace_id
Type used for giving the tablespaces unique number.
Definition: fil0pages_persistence_interface.h:50
virtual void request_sharp_checkpoint()=0
The caller request the implementation to ensure that when it returns, it no longer needs the redo log...
virtual Status assume_checkpoint_lsn(Lsn min_needed_lsn)=0
The caller asks the implementation to assume that redo log below min_needed_lsn is not available and ...
virtual void deinit()=0
Deinitialize whatever was initialized in init().
virtual void page_became_dirty(buf_block_t *buf_block)=0
A callback that is called from buf_flush_note_oldest_modification() once for each page that became di...
virtual ~Pages_persistence_interface()=default
Status
Definition: fil0pages_persistence_interface.h:53
virtual ib::Monitoring_interface & get_monitoring()=0
Returns an object responsible for reporting values of monitors related to pages persistence,...
virtual void redo_delete_tablespace(Tablespace_id space_id, const char *path)=0
Redo a delete tablespace storage operation for a tablespace.
uint32_t Page_number
Type used for numbering the pages in the node.
Definition: fil0tablespace_node_handle_interface.h:42
uint32_t Tablespace_id
Type used for giving the tablespaces unique number.
Definition: fil0tablespaces_nodes_interface.h:40
C++23 std::expected.
Definition: ut0expected.h:74
Definition: ut0function_reference.h:29
ut::unique_ptr< ib::fil::Pages_persistence_interface > pages_persistence
The implementation of persistence for the pages stored in tablespaces' nodes' storage.
Definition: fil0fil.cc:1389
static int flags[50]
Definition: hp_test1.cc:40
static char * path
Definition: mysqldump.cc:151
Definition: fil0fil.cc:1392
void set_pages_persistence(ut::unique_ptr< Pages_persistence_interface > new_persistence)
Sets the implementation of the Pages_persistence_interface.
Definition: fil0fil.cc:1400
uint64_t Lsn
Definition: log0common.h:60
Definition: fil0fil.cc:1392
std::conditional_t< !std::is_array< T >::value, std::unique_ptr< T, detail::Deleter< T > >, std::conditional_t< detail::is_unbounded_array_v< T >, std::unique_ptr< T, detail::Array_deleter< std::remove_extent_t< T > > >, void > > unique_ptr
The following is a common type that is returned by all the ut::make_unique (non-aligned) specializati...
Definition: ut0new.h:2284
The buffer control block structure.
Definition: buf0buf.h:1756
Definition: trx0trx.h:670
Minimal implementation of C++23 std::expected.
Dynamic memory allocation routines and custom allocators specifically crafted to support memory instr...