From e2eeab19ba2d960930815c12f6ed830a4dfa3a45 Mon Sep 17 00:00:00 2001 From: ParadoxV5 Date: Tue, 14 Jul 2026 22:52:36 -0600 Subject: [PATCH] MDEV-39788: Remove added line in `master.info` format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The line-count lines in `master.info` and `relay-log.info` have been inconsistent (off by one) since their introduction. MDEV-37530 “fixed” this with its common code merger by chance, changing `master.info` to use `relay-log.info`’s line-count definition. This change, howëver, affected backward compatibility, as `master.info` now expects an ignored MySQL-only line where the first `key=value` option, `master_use_gtid`, is. Since this legacy text-based format has limitations that make it due for replacement, only code reüsablility is valuable, and its consistency does not outweigh its compatibility. Therefore, this commit solves this problem without reverting code by: * Changing the writing code to be compatible with both interpretations (albeit inconsistent with the reading code) * Adding a shim entry to `master.info`’s list to emulate prior versions’ reading behaviour * Although this solution can only restore upgrade compatibility with versions 10.0+, versions before MariaDB 10 have long been EOL. While here, this commit also fixes code and comments that contradict the actual effect. [P.S.] The test for this regression is pushed to 10.11 in PR #5147. Reviewed-by: Brandon Nesterenko --- sql/rpl_info_file.h | 34 +++++++++++++++++++++------------- sql/rpl_master_info_file.h | 24 +++++++++++++++++++++++- sql/rpl_relay_log_info_file.h | 1 + 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/sql/rpl_info_file.h b/sql/rpl_info_file.h index 493598f7bf5a8..e61fa833a043f 100644 --- a/sql/rpl_info_file.h +++ b/sql/rpl_info_file.h @@ -131,6 +131,14 @@ namespace Int_IO_CACHE Other files may include these files directly. [C++20 modules](https://en.cppreference.com/w/cpp/language/modules.html) can supercede the header-only design as well as headers' `#include` guards. + + @note + It's an old inconsistency that @ref Master_info_file's line count includes + the line-count "value" while @ref Relay_log_info_file's excludes it. + This is reason that Info_file::load_from_file() and + Info_file::save_to_file() defines the line-count lines differently - + It is so the two subclasses can implement either interpretation + on top of the indifferent common code in this superclass. */ struct Info_file { @@ -250,15 +258,15 @@ struct Info_file (Re)load the MySQL line-based section from the @ref file @param value_list List of wrapped member pointers to values. The first element must be a - file name @ref String_value to be unambiguous with the line count line. + file name @ref String_value to be unambiguous with the line-count line. @param default_line_count We cannot simply read lines until EOF as all versions of MySQL/MariaDB may generate more lines than needed. Therefore, starting with MySQL/MariaDB 4.1.x for @ref Master_info_file and - 5.6.x for @ref Relay_log_info_file, the first line of the file is number - of one-line-per-value lines in the file, including this line count itself. + 5.6.x/10.0.x for @ref Relay_log_info_file, the first line of the file is + the number of one-line-per-value lines (excluding itself) in the file. This parameter specifies the number of effective lines before those - versions (i.e., not counting the line count line if it was to have one), + versions (i.e., not counting the line-count line if it was to have one), where the first line is a filename with extension (either contains a `.` or is entirely empty) rather than an integer. @return `false` if the file has parsed successfully or `true` if error @@ -272,14 +280,15 @@ struct Info_file @param value_list List of wrapped member pointers to values. @param total_line_count The number of lines to describe the file as on the first line of the file. - If this is larger than `value_list.size()`, suffix the file with empty - lines until the line count (including the line count line) is this many. - This reservation provides compatibility with MySQL, - who has added more old-style lines while MariaDB innovated. + If this is larger than `size`, suffix the file with empty + lines until the line count (*including* the line-count line) is this many. + (No correction is done if it is less than `size` + 1 for the line-count.) + This reservation provides compatibility + with older versions of MySQL and MariaDB. */ template void save_to_file( const Mem_fn (&value_list)[size], - size_t total_line_count= size + /* line count line */ 1 + size_t total_line_count= size ) { return save_to_file(value_list, size, total_line_count); } private: @@ -336,7 +345,6 @@ struct Info_file void save_to_file(const Mem_fn *values, size_t size, size_t total_line_count) { - DBUG_ASSERT(total_line_count > size); my_b_seek(&file, 0); /* If the new contents take less space than the previous file contents, @@ -355,10 +363,10 @@ struct Info_file } /* Pad additional reserved lines: - (1 for the line count line + line count) inclusive -> max line inclusive - = line count exclusive <- max line inclusive + (1 for the line count line + line count) exclusive -> max line inclusive + = line count exclusive <- max line exclusive */ - for (; total_line_count > size; --total_line_count) + while (--total_line_count > size) my_b_write_byte(&file, '\n'); } diff --git a/sql/rpl_master_info_file.h b/sql/rpl_master_info_file.h index 292f6469b6c69..e49d0f9c55ca5 100644 --- a/sql/rpl_master_info_file.h +++ b/sql/rpl_master_info_file.h @@ -88,6 +88,11 @@ inline uint64_t master_retry_count= 100000; /// }@ +/** + @note The line count includes the line-count line. + Master_info_file::load_from_file() implements this + using @ref Master_info_file::LINE_COUNT_FIX. +*/ struct Master_info_file: Info_file { @@ -540,6 +545,21 @@ struct Master_info_file: Info_file /// }@ +protected: + /** + Info_file::load_from_file() does not include + the line-count "value" in the line count. + The Master_info_file::load_from_file() overload utilizes the presence + of this no-op pseudo-value to emulating counting the line-count "value" - + The driver loop will increment the line counter while this reads nothing. + */ + struct: Persistent + { + bool load_from(IO_CACHE *file) override { return false; } ///< No-op + void save_to(IO_CACHE *file) override {} ///< No-op + } LINE_COUNT_FIX; +public: + inline static const Mem_fn VALUE_LIST[] { &Master_info_file::master_log_file, &Master_info_file::master_log_pos, @@ -561,7 +581,9 @@ struct Master_info_file: Info_file nullptr, // MySQL `master_uuid`, which MariaDB ignores. &Master_info_file::master_retry_count, &Master_info_file::master_ssl_crl, - &Master_info_file::master_ssl_crlpath + &Master_info_file::master_ssl_crlpath, + // This must be last, so its blank line blend into trailing blank line(s). + &Master_info_file::LINE_COUNT_FIX }; /** diff --git a/sql/rpl_relay_log_info_file.h b/sql/rpl_relay_log_info_file.h index 3dbfb2028d14a..9316ad3d42637 100644 --- a/sql/rpl_relay_log_info_file.h +++ b/sql/rpl_relay_log_info_file.h @@ -20,6 +20,7 @@ #include "rpl_info_file.h" +/// @note The line count excludes the line-count line. struct Relay_log_info_file: Info_file { /**