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