MySQL 26.7.0
Source Code Documentation
log0handler_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 <array>
28
30#include "log0common.h"
31#include "ut0dbg.h"
32
33namespace ib::redo {
34
35/**
36This Redo Log Handler interface provides an abstraction over the redo log
37persistence and publishing of the redo log records. The goal here is to wrap
38the existing redo log functionality in the default implementation of this
39interface. The default implementation of this interface is added in the
40`Handler` class.
41*/
43 public:
44 /**
45 Returns the lsn at the requested position that is the end of the MTR data.
46
47 @param[in] start_lsn LSN of the first byte of MTR data in the buffer.
48 @param[in] data_len The Length of the MTR data.
49 @return The LSN at the end of the MTR data in the buffer.
50 */
51 [[nodiscard]] virtual Lsn compute_end_lsn(Lsn start_lsn,
52 size_t data_len) const = 0;
53
54 /** @name Redo Log Handler's Capabilities */
55 /** @{ */
56 struct Capabilities {
57 /** If true, then the implementation supports "atomic writes", which
58 means that if any of the bytes passed to write_mtr(...) becomes available to
59 read() then all of the bytes passed in this call are also available.
60 In other words it's impossible for the Log to appear to end abruptly in
61 between of boundaries of chunks passed to write_mtr(...).
62 Note that it doesn't mean that write_mtr(...) call itself must succeed, or
63 persist the data immediately - it only means that IF and WHEN the data
64 becomes available to read() it must do so in an atomic way.
65 Contrast this with implementation which has atomic_write=false, which may
66 cause a prefix of a buffer passed to write_mtr(...) to become available to
67 the read() - say, due to OS deciding to flush part of the cache to disk and
68 to crash immediately afterwards - forcing the client to carefully analyze
69 data returned by read(..) to detect such unfinished writes.
70 */
72 /** CLONE assumes direct access to files in specific location and format. */
74 /** MEB assumes direct access to files in specific location and format. */
76 /** Is ALTER INSTANCE DISABLE INNODB REDO_LOG supported? */
78 /** True if REDO log encryption is supported */
80 };
81
82 /** Query the capabilities of the Redo Log Handler.
83 This function can be called even before start().
84 @return the capabilities of this Redo Log Handler */
85 [[nodiscard]] virtual Capabilities get_capabilities() = 0;
86
87 /** @} */
88
89 /** @name Log access lifecycle */
90 /** @{ */
91
92 /** Request synchronous creation of Log starting at a given start_lsn.
93 (For historical reasons InnoDB assumes that the first byte of redo log has a
94 particular non-zero value)
95 This function is meant to be called once per "installation" of mysql,
96 typically when `mysqld --initialize` is executed or if the redo log is
97 missing, but the tablespaces are expected to be fully updated,
98 so redo log was logically empty anyway, such as during an upgrade scenario.
99
100 If the log was already created before (say, before the crash/restart) this
101 method should fail with Status::LOG_ALREADY_EXISTS.
102
103 If the function returns SUCCESS the caller may assume that the current
104 `start_lsn` is the most recently written and persisted position.
105
106 @param[in] start_lsn The intended lsn to mark the beginning of the log
107 @return error number or Status::SUCCESS */
108 [[nodiscard]] virtual Status create(Lsn start_lsn) = 0;
109
110 /** Informs Redo Log Handler that the caller intends to start writing to the
111 log. If the log was not yet created, this function should return
112 Status::NO_LOG.
113
114 In case get_capabilities().atomic_write is true, the Redo Log Handler should
115 verify that the start_lsn indeed is the end of the last persisted mtr in the
116 log, and return Status::WRONG_START_LSN otherwise.
117
118 In case get_capabilities().atomic_write is false, the Redo Log Handler should
119 use the provided `start_lsn` to truncate the suffix of the log to start_lsn -
120 the assumption here is that the caller performed recovery using read() API,
121 and has identified the end of the last complete mtr, and anything beyond it is
122 a prefix of a not completely persisted mtr and thus must be discarded. The
123 Redo Log Handler might still perform some rudimentary sanity check such as if
124 the provided start_lsn is not smaller than the last known mtr boundary in the
125 persisted portion of the redo log, or smaller than the last truncate, and
126 return Status::WRONG_START_LSN in such case.
127
128 If the caller has already called start_writing(lsn) before, then this function
129 should fail with Status::WRONG_STATE.
130
131 In case get_capabilities().atomic_write is true, if the caller has called
132 create(lsn), it should return Status::WRONG_START_LSN if lsn!=start_lsn.
133
134 If the function return SUCCESS the caller may assume that the `start_lsn` is
135 the most recently written and persisted position.
136
137 @param[in] start_lsn The lsn the caller believes to be the current end of
138 the log and thus the position at which the next write
139 should start.
140 @return error number or Status::SUCCESS */
141 [[nodiscard]] virtual Status start_writing(Lsn start_lsn) = 0;
142
143 /** Informs Redo Log Handler that the caller no longer intends writing to the
144 log. */
145 virtual void stop_writing() = 0;
146
147 /** Performs any clean up (assumes stop_writing() was already called if
148 start_writing() was) */
149 virtual ~Handler_interface() = default;
150
151 /** @} */
152
153 /** @name Capacity */
154 /** @{ */
155
156 /** InnoDB uses `write_mtr(data,..)` in mtr.commit() when a thread still holds
157 latches on pages involved in the mtr and perhaps other resources. The
158 `write_mtr(..)` may block in case where it can't buffer any more data, and has
159 to write buffered data out, but can't because there's no space left. Such wait
160 under latches is bad for performance, can lead to a crash if continues for
161 long ("long semaphore wait") or even deadlock (if the space can't be
162 reclaimed, because checkpoint can not be advanced, because page cleaners can
163 not write dirty pages to disc, because they can not sx-latch them, because
164 they are still in use by an mtr - either the one doing `write_mtr(..)`, or by
165 one which indirectly waits for some other page or resource which is held by
166 that one).
167
168 To prevent or at least minimize the chance of such wait happening, InnoDB is
169 calling `wait_for_space()` from any thread which wishes to perform
170 `write_mtr(..)`. The caller of `reconfigure(..)` promises there are at most
171 `max_threads` such threads.
172
173 A call to `wait_for_space()` can block, and must be done while not holding any
174 latches, so that waiting will not cascade to other threads. This also implies,
175 that the caller of `wait_for_space()` should not be in a middle of an mtr
176 which holds any latches. The caller of `reconfigure(..)` promises that a
177 thread which has called `wait_for_space()` is permitted to pass at most
178 `reserved_bytes_per_thread` bytes to subsequent calls to `write_mtr(..)`
179 and should call `wait_for_space()` again whenever it needs to write more.
180 For this to work properly the caller of `wait_for_space()` must keep in mind
181 that redo logs accumulated inside an mtr_t object are not properly accounted
182 for by the Handler - the simplest way to avoid problems is to not call
183 `wait_for_space()` while in a middle of an mtr, i.e. before mtr.start(), which
184 is the recommended pattern.
185
186 Additionally InnoDB promises that a thread may call persist_smaller_than()
187 at most once after each call to wait_for_space().
188
189 Under these assumptions, the Handler will do its best to ensure that calls to
190 `write_mtr(..)` will not block, instead throttling the callers of
191 `wait_for_space()` as needed.
192
193 The way this is achieved is up to the Handler, but the contract assumes a
194 model in which Handler returns from `wait_for_space()` only when there's a
195 "margin" sufficient to write `reserved_bytes_per_thread` bytes `max_thread`
196 times ahead of the value of `peek_first_unassigned_lsn()` which the Handler
197 has observed at some moment during the call chosen by the Handler. This
198 phrasing is carefully chosen, as the way this translates to the number of
199 bytes needed on physical storage involves Handler's internal details such as
200 headers, footers and padding, which in turn might depend on frequency of
201 actually persisting data to disc. Note the Handler is allowed (in fact
202 encouraged to) to note the `peek_first_unassigned_lsn()` first, then add the
203 margin to see where it would end physically, and only then start waiting for
204 sufficient amount of old redo logs to be freed, completely ignoring any redo
205 logs which were newly written in parallel while it waits.
206
207 Proof that this approach works is by contradiction: suppose `write_mtr(..)`
208 blocks, despite everyone following the contract. Each finished call to
209 `wait_for_space()` (or a successful call to `has_space()` which from now on
210 will be treated as very quick `wait_for_space()` for simplicity) is associated
211 with a value of `peek_first_unassigned_lsn()` which the Handler used during
212 that call. Let X be the maximum of these associated lsns. Consider all the
213 redo logs above X: they were produced by calls to `write_mtr(..)` from various
214 threads. If any thread finished a call to `wait_for_space()` after one of
215 these `write_mtr(..)` calls, then the Handler would have to use
216 `peek_first_unassigned_lsn()` value which is at least equal to `end_lsn`
217 assigned by `write_mtr(..,end_lsn)`, which would be larger than X, because we
218 focus only on `write_mtr(..,end_lsn)` calls which have end_lsn greater than X.
219 But this would mean this `wait_for_space()` is associated with an lsn larger
220 than X - which contradicts definition of X! So, we have shown that for each
221 finished `write_lsn(..,end_lsn)` with X<end_lsn, there is no finished call to
222 `wait_for_space()` from the same thread sequenced after such `write_lsn()`.
223 This also applies to the thread which is supposedly blocked in `write_mtr(..)`
224 - if it did successful `write_mtr(..)` above X, then it too, could not call
225 `wait_for_space()` later. This means all the calls to `write_mtr(..)` above X,
226 including the one which supposedly block, come from threads which didn't call
227 `wait_for_space()` in between, there are at most `max_threads` of them, each
228 is allowed to write at most `reserved_bytes_per_thread`, and call
229 `persist_smaller_than(..)` at most once above X. By returning from
230 `wait_for_space()` call which is associated with X, the Handler promised, that
231 all of this should fit above X. Yet, we have to wait in `write_mtr(..)` - the
232 contradiction ends the proof.
233
234 The Handler might be unable to satisfy the contract due to the physical
235 constraints such as the permitted max size of files. If so, then the Handler
236 should still do its best to prevent blocking in `write_mtr(..)`, but should
237 return false from `reconfigure(..)` to warn InnoDB that the overall
238 configuration is not "safe".
239
240 @param[in] max_threads
241 The maximum number of threads which can call
242 `write_mtr(..)`.
243 @param[in] reserved_bytes_per_thread
244 The maximum number of bytes a thread may pass to
245 `write_mtr(..)` after a single call to `wait_for_space()`.
246 @return True iff the Handler promises to honor the contract
247 */
248 [[nodiscard]] virtual bool reconfigure(size_t max_threads,
249 size_t reserved_bytes_per_thread) = 0;
250
251 /** Describes the state of the capacity in sufficient detail that InnoDB knows
252 if it should rush with page cleaning and checkpointing. It depicts a
253 hypothetical state at the border between has_space() returning true and false,
254 by providing how much of the redo log history could be retained in this state,
255 and how much of space is reserved for the margin needed by wait_for_space().*/
257 /** The estimated lower bound on the maximum difference between
258 peek_first_unassigned_lsn() and oldest still not removed lsn, which the
259 Handler could keep. */
261 /** The length of the lsn range reserved by wait_for_space(). */
263 /** The so called Soft Logical Capacity, which is the lower bound on the
264 length of the lsn range this Handler can provide to the InnoDB, including
265 the margin needed for wait_for_space(). "Soft" is in contrast to "Hard"
266 limit which might be a little larger, but not exposed to InnoDB, and is the
267 real limit which can't be exceeded for technical reasons, even if the
268 contract of reconfigure(..) and wait_for_space(..) is not followed by
269 InnoDB. "Logical" is in contrast to "Physical" which is the actual number of
270 bytes taken on disc by the data structures.
271
272 Always equal to max_history_length + margin_length. */
273 [[nodiscard]] Lsn soft_logical_capacity() const {
275 }
276 };
277 /** Used by InnoDB to determine if page cleaning and checkpointing should be
278 speed up, because it the lagging checkpoint lsn is the reason we run out of
279 capacity. In order to do that InnoDB is checking what fraction of
280 estimate.soft_logical_capacity() is used up by maintaining redo logs needed
281 by InnoDB, which is:
282 peek_first_unassigned_lsn() + estimate.margin_length - checkpoint_lsn.
283
284 Note: in absolute terms the difference would be the same if we compared
285 estimate.max_history_length to peek_first_unassigned_lsn() - checkpoint_lsn,
286 but for backward-compatibility of all arithmetic expressions InnoDB needs to
287 know the percentage of space usage including the margin.
288
289 As the percentage grows larger, InnoDB employs more and more aggressive page
290 cleaning and checkpoint updating.
291
292 Note: in practice, due to imperfections of following the contract, the
293 percentage may be even larger than 100%. This is handled fine.
294
295 In order to estimate the capacity in a way which is most useful for
296 cooperation with InnoDB, the Handler should imagine reaching a state which is
297 at a boundary between has_space() returning true or false. Note that
298 has_space() takes into account the margin needed for concurrency, and data
299 needed by all consumers known to the Handler, not just InnoDB. In particular,
300 there are two cases:
301
302 (1) If has_space() would return true if called now, then the Handler should
303 try to guess how much more data can be passed to write_mtr(..), before it will
304 return false. The returned estimate.max_history_length should equal
305 "lsn at which has_space() would return false" - "oldest needed lsn now".
306
307 (2) If has_space() would return false now, then imagine how much would data
308 would have to be truncated from disc, before it could return true. The
309 returned estimate.max_history_length should equal
310 "peek_first_unassigned_lsn() now" - "oldest needed lsn after such truncation".
311
312 As for the returned estimate.margin_length it should be the value the Handler
313 uses in wait_for_space() computed based on arguments to reconfigure(..).
314 As explained above, the way this value participates in computation affects
315 both the denominator and numerator in additive way. */
316 [[nodiscard]] virtual Capacity_estimate get_capacity_estimate() = 0;
317
318 /** Called from a thread which wishes to pass no more than
319 `reserved_bytes_per_thread` of data to `write_mtr(..)` in future.
320 InnoDB should prefer to call log_free_check() wrapper instead, as it performs
321 additional verification that the caller shouldn't hold latches.
322 @see reconfigure(size_t max_threads, size_t reserved_bytes_per_thread).
323 There might be at most max_threads using `write_mtr(..)` in InnoDB.
324 The function is called when not holding any latches, and may block until the
325 space for at most reserved_bytes_per_thread is "reserved" for the thread.
326 Note there is no way to "release" the "reserved" space, as the mechanism is
327 rather sophisticated, and assumes an upper bound on the number of threads and
328 number of bytes is enforced by the caller.
329
330 The Handler should behave as if it has noted lsn=peek_first_unassigned_lsn(),
331 and waited for a moment when it could guarantee, that `max_threads` can each
332 pass `reserved_bytes_per_thread` to `write_mtr(..)` calls above that lsn
333 without blocking. @see reconfigure for more details.
334 In case `reconfigure` returned false, the Handler can violate this contract,
335 but still, should do its best to avoid blocking in `write_mtr(..)`.
336
337 Note: in theory you can call it while inside an mtr if it has not yet latched
338 any page, and has no accumulated redo logs or you properly include the
339 already accumulated redo logs within the reserved_bytes_per_thread limit.
340 In practice, it is much simpler and easier to reason about if this function is
341 called *before* mtr.start(). */
342 virtual void wait_for_space() = 0;
343
344 /** This is a no-wait variant of wait_for_space(), i.e. in case
345 wait_for_space() would not have to actually wait, returns true, and the caller
346 might proceed to write at most reserved_bytes_per_thread as if it called
347 wait_for_space(). If this function returns false, the caller must call
348 wait_for_space() before calling write_mtr. As this function doesn't block, the
349 caller is permitted to hold latches when calling it. Still, the caller should
350 rather not be in a middle of an mtr, unless they properly include the redo
351 logs already accumulated within the mtr object in the limit of
352 reserved_bytes_per_thread.
353 @return True iff the caller may proceed to pass reserved_bytes_per_thread
354 bytes to write_mtr without calling wait_for_space(). */
355 [[nodiscard]] virtual bool has_space() = 0;
356
357 /** @} */
358
359 /** @name Log Read */
360 /** @{ */
361
362 /** Informs the Redo Log Handler that InnoDB intends to start reading from the
363 log. In principle it can be a no-op, but in case of InnoDB it actually has a
364 side effect of checking if the files on disc are in correct format/state, and
365 if they are not fully initialized, or in old format, but other than that fine
366 and logically empty, then InnoDB will remove them and pretend they were
367 missing.
368
369 @retval SUCCESS means that there were no issues, and InnoDB can start reading
370 @retval COULD_NOT_OPEN means that the log is missing and the caller should now
371 simply call create(..) and everything should be fine then.
372 @retval READ_ERROR means that the log is somehow broken and can not be read.
373 This is a serious error, which might require manual user action to fix. */
374 [[nodiscard]] virtual Status start_reading() = 0;
375
376 /** Each call to write_mtr(..., &start_lsn, &end_lsn), or create(start_lsn),
377 declares start_lsn to be a boundary between mtrs. Some of such boundaries may
378 be remembered by the Redo Log Handler in its auxiliary metadata (such as block
379 headers) to help to locate a starting point for read operations. This is very
380 important during InnoDB's recovery process, because InnoDB doesn't store the
381 exact checkpoint_lsn value, and the serialization format of mtr doesn't
382 provide a way to start reading from the middle of an mtr, thus InnoDB needs
383 help in finding a boundary between mtrs in the long stream of bytes.
384
385 It is expected that the set of known boundaries is dense enough, that for any
386 given lsn, align_down_to_known_boundary(lsn)-lsn is small enough that starting
387 with read(align_down_to_known_boundary(checkpoint_lsn),...) and then parsing
388 mtrs until we reach checkpoint_lsn (using compute_end_lsn to track progress)
389 will not require too much overhead.
390
391 @return Known boundary LSN if the caller promises to call this function with
392 lsn not smaller than the start_lsn passed to create(start_lsn), nor smaller
393 than the lsn passed to do_not_need_smaller_than(lsn). In other words, the
394 implementation must not forget the oldest boundary LSN that is still needed.
395 Under above conditions, this function must return an mtr boundary not larger
396 than the end_lsn of the mtr which contains the lsn provided by the caller.
397 Note: this means returned value might be slightly larger than lsn, sometimes.
398 If this function doesn't know any mtr boundary which satisfies this condition,
399 which should happen only if the caller violated the contract, it may return 0.
400 */
401 [[nodiscard]] virtual Lsn align_down_to_known_boundary(Lsn lsn) = 0;
402
403 /** Reads previously persisted portion of the Log starting from start_lsn
404 synchronously.
405 By "persisted portion" we mean: if this read() call returns some byte value
406 for a given LSN, then all subsequent calls to read() must return the same byte
407 value for this LSN unless it was already truncated. Note that in case of
408 get_capabilities().atomic_write==false, the start_writing(start_lsn) call may
409 truncate a suffix (from start_lsn onwards) of the log.
410
411 This function will return an error if the start_lsn is already truncated.
412 This function attempts to read as much mtr data as possible to fill the
413 provided buffer, but for performance reasons might decide to return just an
414 initial fragment of the data before filling the buffer completely.
415 In such case buffer.size is adjusted by the API to the actual number of bytes
416 read into the buffer.data.
417 Thus the caller should always check the new value of buffer.size on SUCCESS to
418 know how much data was actually read into the buffer.
419 A Status::SUCCESS implies that at least one byte was read.
420
421 This is in contrast to Status::STREAM_END which means that the end of the Log
422 was reached and no data was read into buffer.data.
423 In other words Status::STREAM_END means that start_lsn is greater than the
424 last persisted lsn and thus no data can be read.
425 In case of return value other than Status::SUCCESS the buffer.size will be set
426 to 0, and no data will be written to the buffer.data.
427 The Status::TORN_STREAM_END is just like STREAM_END in that no data was read
428 into buffer, but additionally conveys that Redo Log Handler failed to reach
429 the end of stream marker. The caller may use this as a hint that the observed
430 end of stream is not a result of a clean shutdown and that some of the data
431 passed to write_mtr(..) wasn't successfully persisted.
432 If get_capabilities().atomic_write is true, then the end of Log must be right
433 after one of the previous write_mtr(...,end_lsn) calls, that is
434 compute_end_lsn(start_lsn, buffer.size)==end_lsn.
435 Conversely, if get_capabilities().atomic_write is false, then:
436 * Status::STREAM_END might be reached in a middle of a range written by
437 write_mtr(..), which also suggests an unclean shutdown, but at least we know
438 that no persisted data was later lost due corruption, as the end of stream
439 marker was successfully reached.
440 * Status::READ_ERROR means that the Handler itself could not obtain the
441 information it needed to determine what's going on, so the caller shouldn't
442 start the server, but rather try to fix the root cause of I/O issues and try
443 again.
444 * OTOH The Status::TORN_STREAM_END means that the Handler has read the
445 data which indicate that the data from recent write got torn (not written
446 successfully) so the readable data definitely ends here but also its visible
447 that there was some attempt to write data after it - this issue is not
448 temporary or fixable on the one hand, but also a bit expected and benign on
449 the other.
450 To give a few examples: file access error, or network error, would be a
451 READ_ERROR. OTOH successfully reading a block from disc or network,
452 which has a header with a checksum field not matching the crc32 of its body is
453 a TORN_STREAM_END, because the underlying low-level read has succeeded, but
454 the content read clearly indicates there was some failure during write.
455
456 If there is no data available the function should report Status::STREAM_END
457 immediately (as opposed to: waiting for more data to be written).
458 Note: because persist_smaller_than(x,..) returns successfully only if the
459 x-1 belongs to the "persisted portion" in the sense defined above, it follows,
460 that data up to and including x-1 should be available for read(..).
461 The read() API can return data even for lsn greater or equal than the x passed
462 to persist_smaller_than(x), but only under condition that it was previously
463 passed to write_mtr() (as opposed to being some made up data) and that if any
464 lsn become available to read() then all lsns before it also become available -
465 in other words: there are no "holes".
466 (Note: there's no requirement that the write_mtr() has successfully returned
467 to the caller. That is a write_mtr() can succeed even if the caller doesn't
468 know that)
469 Additionally, if get_capabilities().atomic_write is true, then if any lsn
470 become available to read() then all other bytes from the same mtr passed to
471 write_mtr(mtr,..,) must be available to read(..) as well - in other words
472 writes are "atomic". To put it in yet another way: if mtr_start_lsn is the
473 first lsn of a given mtr, then the compute_end_lsn(lsn,mtr.data_len)-1 should
474 also be readable.
475
476 Because the ib::redo::Handler assigns Lsns to headers and footers, and
477 read() function retrieves only the bytes of mtrs' bodies, the caller should
478 use compute_end_lsn(start_lsn,i) to compute the lsn value of buffer.data[i].
479 The buffer.data will not contain any headers or footers, just the mtr data.
480
481 @param[in] start_lsn The position from which the read operation should
482 start retrieving bytes (included in the range)
483 @param[in,out] buffer The buffer to store the data read. The buffer.data
484 must point to an array of at least buffer.size bytes
485 owned by the caller. The read(...) function will
486 store up to buffer.size bytes in the buffer.data,
487 starting from buffer.data[0], and will update the
488 buffer.size to match the actual number of bytes
489 written to it.
490 The buffer.data does not need to be aligned.
491 @retval Status::SUCCESS
492 The buffer.size upon return is positive and not larger then before the
493 call, and buffer.data contains buffer.size bytes successfully read
494 from the redo log stream.
495 @retval Status::STREAM_END
496 The buffer.size upon return is 0, indicating, there's no more data in
497 the stream to be read.
498 @retval Status::TORN_STREAM_END
499 The buffer.size upon return is 0, indicating, there's no more data in
500 the stream to be read. Additionally, the handler has determined (by
501 internal consistency checks such as comparing crc32 of block body to
502 the checksum in its header) that there was a torn write attempt at
503 start_lsn.
504 @retval Status::ALREADY_TRUNCATED
505 The start_lsn is older than the currently available redo log data.
506 @retval Status::READ_ERROR
507 The data could not be fetched due to I/O problems. Therefore it is
508 unclear if end of stream was reached or not, but there is no more data
509 that is readable now, and buffer.size is 0 upon return.
510 */
511 [[nodiscard]] virtual Status read(Lsn start_lsn, Buffer &buffer) = 0;
512
513 /** @} */
514
515 /** @name Log Write (only used after calling start_writing(...)) */
516 /** @{ */
517
518 /** Request an asynchronous append of the mtr's body's bytes to the log.
519 The successful call to this function should also assign start_lsn and end_lsn.
520
521 By "append" we also mean that the Redo Log Handler has to promise, that if
522 any of the bytes ever get available to the read(...) operations, then all the
523 bytes before it are also available - in other words: there are no "holes", but
524 some suffix might be missing (for example due to a crash).
525 Additionally, if get_capabilities().atomic_write is true, the write_mtr(..)
526 should be atomic.
527
528 By "atomic" we mean, that if any of the bytes ever get available to the
529 read(..) operations, then all of the other bytes from the same write_mtr(...)
530 call should also be available - in other words: it's all-or-nothing.
531
532 By "asynchronous" we mean that the Redo Log Handler doesn't have to
533 immediately persist the data to the storage medium. It has time up until
534 persist_smaller_than(..) will request it. In case
535 get_capabilities().atomic_write is false, Redo Log Handler may also persist
536 data in fragments not aligned with write_mtr()'s end_lsn. Otherwise, persisted
537 fragment should always be aligned with one of such boundaries.
538 If a failure to persist happens some time after the return from this function,
539 then persist_smaller_than() should fail with an error.
540 The return value should be used to indicate errors determined during the call.
541
542 In case the write_mtr() would require capacity larger than the one currently
543 available the Redo Log Handler it should either block or crash, but it should
544 not return to the caller. The caller may use get_capacity_estimate() to
545 minimize the chance of this happening.
546
547 The caller must call start_writing(...) before calling this function,
548 otherwise it may return Status::WRONG_STATE.
549
550 Due to headers and footers in the Redo Log Handler, the end_lsn - start_lsn,
551 may be larger than the number of bytes in mtr_data, but end_lsn should equal
552 compute_end_lsn(start_lsn, sum of mtr_data[i].count).
553
554 @param[in] mtr_data The mtr's data which should be added to the log.
555 @param[out] start_lsn The position assigned to the first byte by the Redo
556 Log Handler (included in the range).
557 @param[out] end_lsn The next position after the one assigned to the last
558 byte of the mtr (excluded from the range).
559 @return error number or Status::SUCCESS
560 */
561 [[nodiscard]] virtual Status write_mtr(const Const_buffers &mtr_data,
562 Lsn &start_lsn, Lsn &end_lsn) = 0;
563
564 /** Intuitively returns the largest end_lsn assigned from an
565 write_mtr(..,&end_lsn) call. Note that calls to write_mtr() may return in an
566 order different than the order of end_lsn values returned by them.
567 Because there might be concurrent threads which call write_mtr() at any
568 moment, the value returned from this function may be already smaller than an
569 end_lsn already seen by some other thread. Hence it is only a lower bound.
570
571 If the caller knows that a return from write_mtr(..,&end_lsn) has
572 happened-before the call to this function, then the return value must be at
573 least end_lsn.
574
575 If the caller knows that a write_mtr(..,&start_lsn,..) call happens-after the
576 return from this function, then the return value must be at most start_lsn.
577
578 The caller must call start_writing(lsn) before calling this function,
579 otherwise it may return Status::WRONG_STATE. This is because at least in some
580 possible implementations, the exact lsn at which log ends can only be
581 established by performing recovery (reading through whole log till its end),
582 and this is expensive, and requires cooperation with the caller.
583
584 */
586
587 /** Used by persist_smaller_than(...origin) and persist_available(...origin)
588 to let the caller specify the context in which the call is being made, so that
589 an implementation can perform context-specific actions - such as bumping
590 relevant stats. */
591 enum class Origin {
592 /** The call occurs during transaction commit. */
594 /** The call occurs due to page cleaning activity. */
596 /** The call occurs for some other reason. */
597 OTHER,
598 };
599
600 /** Used by persist_smaller_than(...desired_guarantee) to let the caller
601 specify the desired guarantee about persistence before the call returns */
602 enum class Durability {
603 /** A lower level of durability, which only ensures that the data written,
604 should survive, even if the mysqld process crashes, but does not ensure that
605 in case of a failure of something outside the process, such as a crash of
606 the whole OS, or disc, or machine, or a part of Redo Log Handler which is
607 outside current process, say network to its server etc. */
609 /** The default level of durability, which ensures that the data was safely
610 written to a stable storage, so that even a crash or unplugging the cord
611 can prevent the data from being readable. Of course if the stable storage is
612 itself destroyed, then nothing can help. */
614 };
615
616 /** A synchronous request for the Redo Log Handler to promise that previously
617 written data is durable at least up to but not including the end_lsn.
618 By "synchronous" we mean that this function can not return until it can
619 guarantee the data is available to subsequent read(...) calls even after crash
620 (or an error occurs).
621
622 If desired_guarantee is FULLY_PERSISTED the data must reach a secure storage,
623 such that no failure (except of a future damage of the storage itself) can
624 prevent recovery of the data. This is the default behaviour.
625
626 The desired_guarantee can also be OUTLIVE_PROCESS. The Redo Log Handler might
627 simply implement it same way as FULLY_PERSISTED. But, for performance reasons
628 it can choose a faster implementation which does not achieve full persistence,
629 but only a weaker set of guarantees:
630 Provided that the crash/failure is limited just to the mysqld process issuing
631 this call, the lsns below end_lsn should be readable after mysqld restarts.
632 Provided that nothing (neither mysqld, nor Redo Log Handler, nor OS, etc.)
633 crashed the lsns below end_lsn should be readable after this function returns.
634
635 NOTE: This spec of OUTLIVE_PROCESS is a bit fuzzy, but it tries to capture the
636 expectations needed by places which called log_write_up_to(...,sync=false):
637 Arch_Log_Sys::wait_archive_complete()
638 which basically wants to read the redo log files to transmit them over
639 network, so it is sufficient for these files to be considered "written" by
640 the OS, because, any crash would terminate the cloning process anyway, and
641 if there is no crash, then reads should see the writes even if they are
642 still in OS cache.
643 trx_flush_log_if_needed_low()
644 which does not use fsync in cases of:
645 srv_unix_file_flush_method == SRV_UNIX_NOSYNC
646 which is not officially supported setting used for testing performance
647 srv_flush_log_at_trx_commit == 2
648 which is meant to offer a compromise on ACID in which the redo log
649 should be recoverable if the crash was limited to the mysqld process
650 (but the OS, disc, machine survived, so had a chance to fsync).
651 innobase_flush_logs()
652 which does not use fsync in case of being called from
653 MYSQL_BIN_LOG::fetch_and_process_flush_stage_queue() or
654 Commit_order_manager::flush_engine_and_signal_threads()
655 when srv_flush_log_at_trx_commit == 2, because it only needs to provide
656 guarantees similar to those described for trx_flush_log_if_needed_low().
657
658
659 Calling it with end_lsn larger than the end_lsn returned by the most recent
660 successful write_mtr(..,start_lsn,end_lsn) (or start_lsn passed to create()
661 or start_writing() in case no write_mtr() was performed yet) should fail with
662 Status::NOT_WRITTEN_YET.
663
664 The caller must call start_writing(lsn) before calling this function,
665 otherwise it may return Status::WRONG_STATE.
666
667 @param[in] end_lsn
668 The caller wants to wait for all non-truncated bytes at lsns strictly smaller
669 than end_lsn to become persisted.
670
671 @param[in] desired_guarantee
672 The desired durability guarantee.
673
674 @param[in] origin
675 The location from which the call has occurred, which can be used for
676 statistics and other diagnostics
677
678 @return error number or Status::SUCCESS
679 */
680 [[nodiscard]] virtual Status persist_smaller_than(
681 Lsn end_lsn, Durability desired_guarantee = Durability::FULLY_PERSISTED,
682 Origin origin = Origin::OTHER) = 0;
683
684 /** Similar to persist_smaller_than(end_lsn, origin), except that the caller
685 politely asks the Redo Log Handler to persist all that it can persist, without
686 specifying a specific end_lsn as the caller does not really care about any
687 specific lsn being persisted, it just wants to ensure that the value of
688 peek_first_nonpersisted_lsn will become the largest possible now.
689
690 @param[in] origin
691 The location from which the call has occurred, which can be used for
692 statistics and other diagnostics
693
694 @return error number or Status::SUCCESS
695 */
696 [[nodiscard]] virtual Status persist_available(
697 const Origin &origin = Origin::OTHER) = 0;
698
699 /** Intuitively returns the largest end_lsn passed to a successfully finished
700 persist_smaller_than(end_lsn) call. Because there might be concurrent threads
701 which call persist_smaller_than() at any moment, the value returned from this
702 function may be already smaller than an end_lsn already passed by some other
703 thread. Hence it is only a lower bound.
704 Also, the Redo Log Handler might voluntarily persist next portion of the
705 log in the background even if persist_smaller_than() wasn't called, so the
706 returned value doesn't really have to be equal to the most recent value passed
707 to persist_smaller_than(end_lsn).
708 Also, for get_capabilities().atomic_write=true case, the persisted range of
709 lsns is always aligned with mtr boundary, which implies that the Redo Log
710 Handler has to persist more than requested when unaligned lsn is passed to
711 persist_smaller_than(lsn).
712
713 If the caller knows that a return from persist_smaller_than(end_lsn) has
714 happened-before the call to this function, then the return value must be at
715 least end_lsn.
716
717 The caller must call start_writing(lsn) before calling this function,
718 otherwise it may return Status::WRONG_STATE. This is because at least in some
719 possible implementations, the exact lsn at which persisted fragment of the log
720 ends can only be established by performing recovery (reading through whole log
721 til its end), and this is expensive, and requires cooperation with the caller.
722
723 */
724 [[nodiscard]] virtual Lsn peek_first_nonpersisted_lsn() = 0;
725
726 /* An asynchronous permission to delete a prefix of the Log up to but not
727 including align_down_to_known_boundary(needed_lsn) [That is, the byte at
728 align_down_to_known_boundary(needed_lsn) should not be removed]. This is the
729 way in which InnoDB lets the Redo Log Handler know that it no
730 longer needs data below this lsn. It should return immediately even if the
731 garbage collection process takes longer.
732
733 The caller must call start_writing(lsn) before calling this function,
734 otherwise it may return Status::WRONG_STATE.
735
736 It is an error to pass needed_lsn which is larger than last persisted lsn+1.
737 (Last persisted lsn is at least as large as the end_lsn-1 where end_lsn is the
738 value passed to last successful persist_smaller_than(end_lsn,...) call. Taken
739 together it means it is ok to call do_not_need_smaller_than(end_lsn) but a
740 larger value may fail with Status::NOT_WRITTEN_YET.) The Redo Log Handler can
741 delete data up to and including needed_lsn-1, or some arbitrarily shorter
742 prefix of it, which the user of the API will not be able to tell anyway,
743 because by calling do_not_need_smaller_than(x) the caller promises to never
744 call read(..start_lsn,..) with start_lsn < align_down_to_known_boundary(x)
745 - such a read may fail with Status::ALREADY_TRUNCATED. In particular,
746 the Redo Log Handler does not need to ensure that data is removed exactly up
747 to x nor to a position aligned to a write boundary - any value
748 y <= align_down_to_known_boundary(x) should be fine, as it is a responsibility
749 of the user of the API to correctly find a
750 point >= align_down_to_known_boundary(x) at which it wants to start reading.
751 NOTE: Calling it with a value smaller than the one passed to an earlier call
752 to this function is permitted and results in immediate Status::SUCCESS, but
753 may indicate some issue in the InnoDB's implementation.
754
755 The Redo Log Handler must ensure that after truncation there will still be at
756 least one known mtr boundary with lsn <= needed_lsn - i.e. that a call to
757 align_down_to_known_boundary(needed_lsn) will not fail. One way to achieve it
758 is to avoid truncating past the last known boundary before needed_lsn.
759
760 @param[in] needed_lsn The smallest needed lsn. All data at smaller lsns can
761 be deleted by Redo Log Handler, as the user of the API
762 will not attempt to ever read it again.
763 @return error number or Status::SUCCESS
764 */
765 [[nodiscard]] virtual Status do_not_need_smaller_than(Lsn needed_lsn) = 0;
766
767 /** @} */
768
769 /** @name Log Metadata */
770 /** @{ */
771
772 /** We abstract the Log Metadata - the data associated with the whole Log, as
773 opposed to the data stored in the log's stream itself which is accessed by
774 write() and read()) - as Blocks of bytes associated with keys 0,..,MAX_KEY,
775 which the Redo Log Handler does not interpret in any way, just atomically
776 stores and retrieves when requested. There are exactly MAX_KEY+1 Blocks, 512
777 bytes each. */
778
779 /** The maximum possible value for first argument to store_metadata(key,..)
780 and load_metadata(key,..). */
781 static constexpr uint16_t MAX_KEY = 1;
782
783 /** Each metadata block has the same fixed size of 512 bytes. */
784 static constexpr uint32_t METADATA_BLOCK_SIZE = 512;
785 using Metadata_value = std::array<unsigned char, METADATA_BLOCK_SIZE>;
786
787 /** Persists synchronously the metadata atomically overwriting the old value
788 for a given key.
789 By "atomically" we mean that the Redo Log Handler has to ensure that in case
790 of a crash either the old value of metadata or the new value of metadata will
791 be returned for the given key (no "torn writes"). By "synchronous" we mean
792 that the call can not return to the caller until the operation is complete (or
793 failed). In case of success, calls to get_metadata(key) should see this or
794 newer value.
795
796 It must be called only after successful create() or start_writing().
797
798 @param[in] key A value in range 0,...,MAX_KEY inclusive.
799 @param[in] value The 512 bytes to be persisted as associated with the key.
800 @return error number or Status::SUCCESS
801 */
802 [[nodiscard]] virtual Status store_metadata(uint16_t key,
803 const Metadata_value &value) = 0;
804
805 /** Retrieves the previously stored metadata block for a given key.
806 The Redo Log Handler must guarantee that if the get_metadata(key, &r)
807 happens-after the call to store_metadata(key, &w), then the content of r will
808 be that of w, or from some later store. If there was no previous
809 store_metadata for a given key, should fail with Status::METADATA_IS_MISSING.
810
811 It must be called only after successful start_reading(...) or start_writing().
812
813 @param[in] key A value in range 0,...,MAX_KEY inclusive.
814 @param[out] value The 512 bytes buffer to store the retrieved metadata.
815 @return error number or Status::SUCCESS
816 */
817 [[nodiscard]] virtual Status get_metadata(uint16_t key,
818 Metadata_value &value) = 0;
819
820 /** @} */
821
822 /** Returns the handler to configure the redo log related system variables.
823
824 @return Object of type Sys_var_handler_interface
825 */
826 [[nodiscard]] virtual Sys_var_handler_interface &config_handler() = 0;
827};
828
829/** Sets the concrete Redo Log Handler to be used.
830 @param[in] handler A Redo Log Handler Object */
832
834
835} // namespace ib::redo
836
837/** A wrapper for ib::redo::handler->wait_for_space(), which should be used in
838InnoDB code, as it verifies that InnoDB doesn't hold latches which could cause
839deadlocks. @see ib::redo::Handler_interface::wait_for_space(). */
840void log_free_check();
The handler class is the interface for dynamically loadable storage engines.
Definition: handler.h:4753
Definition: ha0sys_var_handler_interface.h:36
This Redo Log Handler interface provides an abstraction over the redo log persistence and publishing ...
Definition: log0handler_interface.h:42
static constexpr uint16_t MAX_KEY
We abstract the Log Metadata - the data associated with the whole Log, as opposed to the data stored ...
Definition: log0handler_interface.h:781
virtual Lsn align_down_to_known_boundary(Lsn lsn)=0
Each call to write_mtr(..., &start_lsn, &end_lsn), or create(start_lsn), declares start_lsn to be a b...
virtual Status do_not_need_smaller_than(Lsn needed_lsn)=0
virtual Status persist_smaller_than(Lsn end_lsn, Durability desired_guarantee=Durability::FULLY_PERSISTED, Origin origin=Origin::OTHER)=0
A synchronous request for the Redo Log Handler to promise that previously written data is durable at ...
virtual ~Handler_interface()=default
Performs any clean up (assumes stop_writing() was already called if start_writing() was)
virtual Status get_metadata(uint16_t key, Metadata_value &value)=0
Retrieves the previously stored metadata block for a given key.
Durability
Used by persist_smaller_than(...desired_guarantee) to let the caller specify the desired guarantee ab...
Definition: log0handler_interface.h:602
@ OUTLIVE_PROCESS
A lower level of durability, which only ensures that the data written, should survive,...
@ FULLY_PERSISTED
The default level of durability, which ensures that the data was safely written to a stable storage,...
static constexpr uint32_t METADATA_BLOCK_SIZE
Each metadata block has the same fixed size of 512 bytes.
Definition: log0handler_interface.h:784
virtual Capacity_estimate get_capacity_estimate()=0
Used by InnoDB to determine if page cleaning and checkpointing should be speed up,...
Origin
Used by persist_smaller_than(...origin) and persist_available(...origin) to let the caller specify th...
Definition: log0handler_interface.h:591
@ OTHER
The call occurs for some other reason.
@ PAGE_FLUSHING
The call occurs due to page cleaning activity.
@ TRX_COMMIT
The call occurs during transaction commit.
virtual void wait_for_space()=0
Called from a thread which wishes to pass no more than reserved_bytes_per_thread of data to write_mtr...
virtual Status start_writing(Lsn start_lsn)=0
Informs Redo Log Handler that the caller intends to start writing to the log.
virtual Status store_metadata(uint16_t key, const Metadata_value &value)=0
Persists synchronously the metadata atomically overwriting the old value for a given key.
virtual Status start_reading()=0
Informs the Redo Log Handler that InnoDB intends to start reading from the log.
virtual Sys_var_handler_interface & config_handler()=0
Returns the handler to configure the redo log related system variables.
virtual Lsn peek_first_nonpersisted_lsn()=0
Intuitively returns the largest end_lsn passed to a successfully finished persist_smaller_than(end_ls...
virtual Status persist_available(const Origin &origin=Origin::OTHER)=0
Similar to persist_smaller_than(end_lsn, origin), except that the caller politely asks the Redo Log H...
std::array< unsigned char, METADATA_BLOCK_SIZE > Metadata_value
Definition: log0handler_interface.h:785
virtual Capabilities get_capabilities()=0
Query the capabilities of the Redo Log Handler.
virtual Status create(Lsn start_lsn)=0
Request synchronous creation of Log starting at a given start_lsn.
virtual Lsn compute_end_lsn(Lsn start_lsn, size_t data_len) const =0
Returns the lsn at the requested position that is the end of the MTR data.
virtual Lsn peek_first_unassigned_lsn()=0
Intuitively returns the largest end_lsn assigned from an write_mtr(..,&end_lsn) call.
virtual Status write_mtr(const Const_buffers &mtr_data, Lsn &start_lsn, Lsn &end_lsn)=0
Request an asynchronous append of the mtr's body's bytes to the log.
virtual bool reconfigure(size_t max_threads, size_t reserved_bytes_per_thread)=0
InnoDB uses write_mtr(data,..) in mtr.commit() when a thread still holds latches on pages involved in...
virtual void stop_writing()=0
Informs Redo Log Handler that the caller no longer intends writing to the log.
virtual Status read(Lsn start_lsn, Buffer &buffer)=0
Reads previously persisted portion of the Log starting from start_lsn synchronously.
virtual bool has_space()=0
This is a no-wait variant of wait_for_space(), i.e.
void log_free_check()
A wrapper for ib::redo::handler->wait_for_space(), which should be used in InnoDB code,...
Definition: log0free_check.cc:62
Definition: log0common.h:32
Status
Additional error constants may be added to the list here, keeping in mind the following guidelines ab...
Definition: log0common.h:102
Handler_interface * handler
Definition: log0log.cc:434
uint64_t Lsn
Definition: log0common.h:60
std::span< uint8_t > Buffer
Definition: log0common.h:123
void set_handler(Handler_interface *handler)
Sets the concrete Redo Log Handler to be used.
Definition: log0log.cc:581
ValueType value(const std::optional< ValueType > &v)
Definition: gtid.h:83
mutable_buffer buffer(void *p, size_t n) noexcept
Definition: buffer.h:418
required string key
Definition: replication_asynchronous_connection_failover.proto:60
Definition: log0common.h:125
Definition: log0handler_interface.h:56
bool atomic_write
If true, then the implementation supports "atomic writes", which means that if any of the bytes passe...
Definition: log0handler_interface.h:71
bool supports_encryption
True if REDO log encryption is supported.
Definition: log0handler_interface.h:79
bool supports_disabling
Is ALTER INSTANCE DISABLE INNODB REDO_LOG supported?
Definition: log0handler_interface.h:77
bool supports_meb
MEB assumes direct access to files in specific location and format.
Definition: log0handler_interface.h:75
bool supports_clone
CLONE assumes direct access to files in specific location and format.
Definition: log0handler_interface.h:73
Describes the state of the capacity in sufficient detail that InnoDB knows if it should rush with pag...
Definition: log0handler_interface.h:256
Lsn margin_length
The length of the lsn range reserved by wait_for_space().
Definition: log0handler_interface.h:262
Lsn max_history_length
The estimated lower bound on the maximum difference between peek_first_unassigned_lsn() and oldest st...
Definition: log0handler_interface.h:260
Lsn soft_logical_capacity() const
The so called Soft Logical Capacity, which is the lower bound on the length of the lsn range this Han...
Definition: log0handler_interface.h:273
Debug utilities for Innobase.
static uint64_t lsn
Definition: xcom_base.cc:446