/** @return whether recovery is currently running. */ #define recv_recovery_is_on() UNIV_UNLIKELY(recv_sys.recovery_on)
ATTRIBUTE_COLD MY_ATTRIBUTE((nonnull, warn_unused_result)) /** Apply any buffered redo log to a page. @paramspacetablespace @parambpagebufferpoolpage
@return whether the page was recovered correctly */ bool recv_recover_page(fil_space_t* space, buf_page_t* bpage);
/** Start recovering from a redo log checkpoint. offirstsystemtablespacepage
@return error code or DB_SUCCESS */
dberr_t recv_recovery_from_checkpoint_start();
/** Report an operation to create, delete, or rename a file during backup. @param[in]space_idtablespaceidentifier @param[in]typefileoperationredologtype @param[in]namefilename(notNUL-terminated) @param[in]lenlengthofname,inbytes @param[in]new_namenewfilename(NULLifnotrename)
@param[in] new_len length of new_name, in bytes (0 if NULL) */ externvoid (*log_file_op)(uint32_t space_id, int type, const byte* name, ulint len, const byte* new_name, ulint new_len);
/** Report an operation which does undo log tablespace truncation duringbackup
@param space_id undo tablespace identifier */ externvoid (*undo_space_trunc)(uint32_t space_id);
/** Report an operation which does INIT_PAGE for page0 during backup.
@param space_id tablespace identifier */ externvoid (*first_page_init)(uint32_t space_id);
/** Find a doublewrite copy of a page with the smallest FIL_PAGE_LSN thatislargeenoughforrecovery. @parampage_idpageidentifier @parammax_lsnthemaximumallowedLSN @paramspacetablespace(nullptrforpage_id.page_no()==0) @paramtmp_buf2*srv_page_sizefordecryptinganddecompressingany page_compressedorencryptedpages @returnpageframe
@retval nullptr if no valid page for page_id was found */ const byte *find_page(const page_id_t page_id, lsn_t max_lsn, const fil_space_t *space= nullptr,
byte *tmp_buf= nullptr) const noexcept;
/** Find the doublewrite copy of an encrypted/page_compressed pagewiththesmallestFIL_PAGE_LSNthatislargeenoughfor recovery. @paramspacetablespaceobject @parampage_nopagenumbertofind @parambufbufferforunencrypted/uncompressedpage @returnbuf
@retval nullptr if the page was not found in doublewrite buffer */
ATTRIBUTE_COLD byte *find_deferred_page(const fil_node_t &space,
uint32_t page_no,
byte *buf) noexcept;
/** Restore the first page of the given tablespace from doublewritebuffer. 1)Findthepagewhichhaspage_noas0 2)Readfirst3pagesfromtablespacefile 3)Comparethespace_idsfromthepageswithpage0which wasretrievedfromdoublewritebuffer @paramnametablespacefilepath @paramfiletablespacefilehandle
@return space_id or 0 in case of error */ inline uint32_t find_first_page(constchar *name, pfs_os_file_t file) const noexcept;
/** Recovered doublewrite buffer page frames */
list pages;
};
/** recv_sys.pages entry; protected by recv_sys.mutex */ struct page_recv_t
{ /** Recovery status: 0=not in progress, 1=log is being applied, -1=loghasbeenappliedandtheentrymaybeerased.
Transitions from 1 to -1 are NOT protected by recv_sys.mutex. */
Atomic_relaxed<int8_t> being_processed{0}; /** Whether reading the page will be skipped */ bool skip_read= false; /** Latest written byte offset when applying the log records.
@see mtr_t::m_last_offset */
uint16_t last_offset= 1; /** log records for a page */ class recs_t
{ /** The first log record */
log_rec_t *head= nullptr; /** The last log record */
log_rec_t *tail= nullptr; friendstruct page_recv_t; public: /** Append a redo log snippet for the page
@param recs log snippet */ void append(log_rec_t* recs)
{ if (tail)
tail->next= recs; else
head= recs;
tail= recs;
} /** Remove the last records for the page
@param start_lsn start of the removed log */
ATTRIBUTE_COLD void rewind(lsn_t start_lsn);
/** @return the last log snippet */ const log_rec_t* last() const { return tail; } /** @return the last log snippet */
log_rec_t* last() { return tail; }
/** Trim old log records for a page. @paramstart_lsnoldestlogsequencenumbertopreserve
@return whether all the log for the page was trimmed */ inlinebool trim(lsn_t start_lsn); /** Ignore any earlier redo log records for this page. */ inlinevoid will_not_read();
};
/** Recovery system data structure */ struct recv_sys_t
{ /** mutex protecting this as well as some of page_recv_t */
alignas(CPU_LEVEL1_DCACHE_LINESIZE) mysql_mutex_t mutex; private: /** set when finding a corrupt log block or record, or there is a
log parsing buffer overflow */ bool found_corrupt_log; /** set when an inconsistency with the file system contents is detected
during log scan or apply */ bool found_corrupt_fs; public: /** @return maximum guaranteed size of a mini-transaction on recovery */ static constexpr size_t MTR_SIZE_MAX{1U << 20};
/** whether we are applying redo log records during crash recovery. Thiscanbeclearedwhenholdingmutex,orwhenpages.empty()and weareholdingexclusivelog_sys.latch.Whenthisisset, buf_flush_page_cleaner()willnotinvokelog_checkpoint_low(), buf_pool.flush_listmaybeunsortedbybuf_page_t::oldest_modification(),
and garbage_collect() replaces buf_pool_t::running_out(). */
Atomic_relaxed<bool> recovery_on= false; /** whether recv_recover_page(), invoked from buf_page_t::read_complete(),
should apply log records*/ bool apply_log_recs:1; /** whether a circular log was recovered with archive file name */ bool was_archive:1; /** number of bytes in log_sys.buf */
size_t len; /** start offset of non-parsed log records in log_sys.buf */
size_t offset; /** start offset of the currently parsed mini-transaction */
size_t start_offset; /** log sequence number of the first non-parsed record */
lsn_t lsn; /** log sequence number at the start of parse_tail() */
lsn_t start_lsn; /** log sequence number of the last parsed mini-transaction */
lsn_t scanned_lsn; /** log sequence number at the end of the FILE_CHECKPOINT record, or 0 */
lsn_t file_checkpoint; /** recovery start checkpoint */
lsn_t recovery_start; /** recovery point objective (a limit for scanned_lsn) */
lsn_t rpo;
/** the time when progress was last reported */
time_t progress_time;
/** an innodb_log_archive=ON file available for recovery */ struct archive_log
{ /** the LSN that is past the end of the file; derived from
the start LSN and the file size */ const lsn_t end; /** READ_WRITE or READ_ONLY, initially derived from the file permissions. Infind_checkpoint(),allbutthelastfilewillbemarkedREAD_ONLY.
Also the last file may be marked READ_ONLY if recv_sys.rpo is set. */ const log_t::log_access access;
}; /** map of innodb_log_archive=ON files, indexed by the start LSN */ using archive_map = std::map<const lsn_t, const archive_log>; /** innodb_log_archive=ON files, with no gaps before the last file */
archive_map log_archive;
using map = std::map<const page_id_t, page_recv_t,
std::less<const page_id_t>,
ut_allocator<std::pair<const page_id_t, page_recv_t>>>; /** buffered records waiting to be applied to pages */
map pages;
private: /** iterator to pages, used by parse() */
map::iterator pages_it;
/** The allocated size of tmp_buf. The 1+8 extra bytes are
needed for FORMAT_ENC_11 in parse(). */ static constexpr size_t tmp_buf_size{MTR_SIZE_MAX + 9}; /** buffer for decrypting mini-transactions or handling non-contiguous
mini-transactions */
byte *tmp_buf;
/** Process a record that indicates that a tablespace size is being shrunk. @parampage_idfirstpagethatisnotinthefile
@param lsn log sequence number of the shrink operation */
ATTRIBUTE_COLD void trim(const page_id_t page_id, lsn_t lsn);
/** Undo tablespaces for which truncate has been logged
(indexed by page_id_t::space() - srv_undo_space_id_start) */ struct trunc
{ /** log sequence number of FILE_CREATE, or 0 if none */
lsn_t lsn; /** truncated size of the tablespace, or 0 if not truncated */ unsigned pages;
};
/** Advance pages_it if it matches the iterator */ void pages_it_invalidate(const map::iterator &p) noexcept
{
mysql_mutex_assert_owner(&mutex); if (pages_it == p)
pages_it++;
} /** Invalidate pages_it if it points to the given tablespace */ void pages_it_invalidate(uint32_t space_id) noexcept
{
mysql_mutex_assert_owner(&mutex); if (pages_it != pages.end() && pages_it->first.space() == space_id)
pages_it= pages.end();
}
/** Allow to apply system tablespace truncate redo log only ifthesizetobeextendedislesserthancurrentsize. @retvaltrueToapplythetruncateshrinkredologrecord
@retval false otherwise */ bool check_sys_truncate();
private: /** In parse_tail<storing=NO>(), handle INIT_PAGE or FREE_PAGE
@param id page that is being initialized or freed */ void parse_init(const page_id_t id) noexcept;
/** Handle WRITE to FSP_SPACE_SIZE and FSP_SPACE_FLAGS. @paramidtablespaceheaderpage @paramblogrecordsnippet @paramsizewhetherFSP_SPACE_SIZEisbeingchanged
@param flags whether FSP_SPACE_FLAGS is being changed */ void parse_page0(const page_id_t id, const byte *b, bool size, bool flags)
noexcept;
/** Pass a binlog recovery record to the binlog implementation. @paramspace_idbinlogfileidentifier @paralllogrecord @paramrlenrecordlength @parampage_nopagemodifiedbytherecord @paramstart_lsnLSNatstartofrecord @paramlsnLSNatendofrecord
@return whether record was found corrupt */ bool parse_store_binlog(uint32_t space_id, const byte *l, uint32_t rlen,
uint32_t page_no, lsn_t start_lsn, lsn_t lsn);
/** @return whether parse_store() needs to be invoked
@param space_id tablespace identifier */ bool parse_store_if_exists(uint32_t space_id) const noexcept;
/** Store a parsed log record. @paramidpageidentifier @paramllogrecord @paramsizesizeofthelogrecord
@return whether we ran out of memory */ bool parse_store(const page_id_t id, const byte *l, size_t size) noexcept;
/** Attempt to initialize a page based on redo log records. @parampiterator @parammtrmini-transaction @parambpre-allocatedbufferpoolblock @paraminit_lsnpageinitialization @returntherecoveredblock @retvalnullptrifthepagecannotbeinitializedbasedonlogrecords
@retval -1 if the page cannot be recovered due to corruption */ inline buf_block_t *recover_low(const map::iterator &p, mtr_t &mtr,
buf_block_t *b, lsn_t init_lsn);
/** All found log files (multiple ones are possible if we are upgrading
from before MariaDB Server 10.5.1) */
std::vector<log_file_t> files;
/** Base node of the redo block list.
List elements are linked via buf_block_t::unzip_LRU. */
UT_LIST_BASE_NODE_T(buf_block_t) blocks;
/** Allocate a block from the buffer pool for recv_sys.pages */
ATTRIBUTE_COLD buf_block_t *add_block();
/** Wait for buffer pool to become available.
@param pages number of buffer pool pages needed */
ATTRIBUTE_COLD void wait_for_pool(size_t pages);
/** Free log for processed pages. */ void garbage_collect();
/** Apply a recovery batch. @paramspace_idcurrenttablespaceidentifier @paramspacecurrenttablespace @paramfree_blocksparebufferblock @paramlast_batchwhetheritispossibletowritemoreredolog
@return whether the caller must provide a new free_block */ bool apply_batch(uint32_t space_id, fil_space_t *&space,
buf_block_t *&free_block, bool last_batch);
public: /** Apply buffered log to persistent data pages.
@param last_batch whether it is possible to write more redo log */ void apply(bool last_batch);
#ifdef UNIV_DEBUG /** whether all redo log in the current batch has been applied */ bool after_apply= false; #endif /** Initialize the redo log recovery subsystem. */ void create();
/** Free most recovery data structures. */ void debug_free();
/** Find the latest checkpoint.
@return error code or DB_SUCCESS */
dberr_t find_checkpoint();
private: /** Find a checkpoint in an innodb_log_archive=ON file. @paramfirst_lsnthefirstLSNofthefile @paramsilentwhethertosilenceerrorreporting @returnerrorcode
@retval DB_SUCCESS if a suitable checkpoint was found */
dberr_t find_checkpoint_archived(lsn_t first_lsn, bool silent); public:
/** Register a redo log snippet for a page. @paramitpageiterator @paramlredologsnippet @paramlenlengthofl,inbytes
@return whether we ran out of memory */ bool add(map::iterator it, const byte *l, size_t len);
/** Parsing result */ enum parse_mtr_result { /** a record was successfully parsed */
OK, /** the log ended prematurely (need to read more) */
PREMATURE_EOF, /** the end of the log was reached */
GOT_EOF, /** parse<YES>(l, false) ran out of memory */
GOT_OOM
};
/** Whether to store parsed log records */ enum store{NO,BACKUP,YES};
private: /** Parse and register one mini-transaction. @tparamsourcetypeoflogdatasource @tparamstoringwhethertostoretherecords @tparamformatlogrecordformat(log_sys.format) @paramllogdatasource
@param if_exists if store: whether to check if the tablespace exists */ template<typename source,store storing,uint32_t format> inline __attribute__((always_inline))
parse_mtr_result parse(source l, bool if_exists) noexcept;
/** Report that multi-batch recovery is needed.
@retval GOT_OOM always */
parse_mtr_result parse_oom() noexcept;
/** Parse and register one mini-transaction. @tparamENC_10_8whetherthisinlog_t::FORMAT_ENC_10_8 @tparamstoringwhethertostoretherecords @parambeginstartofthemini-transaction @paramif_existsifstore:whethertocheckifthetablespaceexists @paramsizesizeofthemini-transaction @retvalOKonsuccess @retvalGOT_EOFoncorruption
@retval GOT_OOM if we ran out of memory for recv_sys.pages */ template<bool ENC_10_8,recv_sys_t::store storing>
parse_mtr_result parse_tail(const byte *begin, bool if_exists, size_t size)
noexcept;
/** Rewind a mini-transaction when parse_tail() runs out of memory. @parambeginstartofthemini-transaction
@param end start of the first unprocessed record */
ATTRIBUTE_COLD void rewind(const byte *begin, const byte *end) noexcept;
/** Report progress in terms of LSN or pages remaining */
ATTRIBUTE_COLD void report_progress() const; /** Parse and register a mini-transaction, withouthandlinganylog_sys.is_mmap()bufferwrap-around. @tparamstoringwhethertostoretherecords @tparamformatlog_sys.format
@param if_exists storing=YES: whether to check if the tablespace exists */ template<store storing,uint32_t format> static parse_mtr_result parse_mtr(bool if_exists); public: /** Parse and register a mini-transaction, handlinglog_sys.is_mmap()bufferwrap-around. @tparamstoringwhethertostoretherecords @tparamformatlog_sys.format
@param if_exists storing=YES: whether to check if the tablespace exists */ template<store storing,uint32_t format> static parse_mtr_result parse_mmap(bool if_exists); /** mini-transaction parser */ using parser= parse_mtr_result(*)(bool if_exists); /** @return the parsing function for mariadb-backup --backup */ static parser get_backup_parser() noexcept;
/** Erase log records for a page. */ void erase(map::iterator p);
/** Clear a fully processed set of stored redo log records. */ void clear();
/** Determine whether redo log recovery progress should be reported. @paramtimethecurrenttime @returnwhetherprogressshouldbereported
(the last report was at least 15 seconds ago) */ bool report(time_t time);
/** The alloc() memory alignment, in bytes */ static constexpr size_t ALIGNMENT= sizeof(size_t);
/** Free a redo log snippet.
@param data buffer allocated in add() */ inlinevoid free(constvoid *data);
/** Remove records for a corrupted page. @parampage_idcorruptedpageidentifier @paramnodefileforwhichanerroristobereported
@return whether an error message was reported */
ATTRIBUTE_COLD bool free_corrupted_page(page_id_t page_id, const fil_node_t &node) noexcept;
/** Flag data file corruption during recovery. */
ATTRIBUTE_COLD void set_corrupt_fs() noexcept; /** Flag log file corruption during recovery.
@retval GOT_EOF always */
ATTRIBUTE_COLD parse_mtr_result set_corrupt_log() noexcept;
/** @return whether data file corruption was found */ bool is_corrupt_fs() const { return UNIV_UNLIKELY(found_corrupt_fs); } /** @return whether log file corruption was found */ bool is_corrupt_log() const { return UNIV_UNLIKELY(found_corrupt_log); }
/** Check if recovery reached a consistent log sequence number.
@return whether the recovery failed to process enough log */ inlinebool validate_checkpoint() const noexcept;
/** Read a page or recover it based on redo log records. @parampage_idpageidentifier @parammtrmini-transaction @paramerrerrorcode @returntherequestedblock
@retval nullptr if the page cannot be accessed due to corruption */
ATTRIBUTE_COLD
buf_block_t *recover(const page_id_t page_id, mtr_t *mtr, dberr_t *err);
/** Try to recover a tablespace that was not readable earlier @parampiterator @paramnametablespacefilename @paramfree_blocksparebufferblock @returnrecoveredtablespace
@retval nullptr if recovery failed */
fil_space_t *recover_deferred(const map::iterator &p, const std::string &name,
buf_block_t *&free_block);
};
/** The recovery system */ extern recv_sys_t recv_sys;
/** TRUE when recv_init_crash_recovery() has been called. */ externbool recv_needed_recovery; #ifdef UNIV_DEBUG /** whether writing to the redo log is forbidden;
protected by exclusive log_sys.latch. */ externbool recv_no_log_write; #endif/* UNIV_DEBUG */
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.