1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00
Files
mariadb/sql/rpl_info_file.h
Monty c7032278d4 Remove C++ STL machinery from sql/rpl_*info_file.* and CHANGE MASTER parser
Replaces std::function / std::optional / std::unordered_map /
std::unordered_set / std::string_view and template-heavy code in the
master.info / relay-log.info persistence layer with plain MariaDB
idioms.
- On-disk file format unchanged.
- SQL syntrax unchanged
- No notable test changes, except those for which new error messages was
  added and output from SHOW VARIABLES.
- master_* CLI options moved from inline globals in
  rpl_master_info_file.h to Sys_var_* in sys_vars.cc (READ_ONLY,
  AUTO_SET on use_gtid and heartbeat_period). master_heartbeat_period
  is Sys_var_double (seconds); master_use_gtid is Sys_var_enum. Global
  storage sits outside HAVE_REPLICATION so libmariadbd links.
   - This adds the rpl_master_info variables to SHOW VARIABLES
- Value classes are no longer templates. Persistent renamed to Value;
  Optional_* classes renamed (Uint_value_with_default, Path_value,
  etc.).  has_value flag in the base; is_default()
  non-virtual. Multi-line method bodies moved to new rpl_info_file.cc
  and rpl_master_info_file.cc.
- VALUE_LIST (Mem_fn array) and VALUE_MAP (std::unordered_map)
  replaced by per-instance Value *const value_list[] / value_map[]
  arrays + a static TYPELIB populated at first construction from each
  Value's variable_name. seen-set dedup is now a uint32 bitmask.
- Default handling is not anymore done with using special values.
  Setting a value to default is now done by calling set_default(),
  which sets the has_value member to 0 and stores the default value
  in the variable.
  When reading a value, one does not have to check if the value is
  a default value.
  This makes the interface cleaner and easier to manage.
- CHANGE MASTER TO parser no longer builds std::function lambdas:
  LEX_MASTER_INFO carries mi_used_options / mi_used_default bitmasks
  plus plain value fields; change_master() applies them via bit-test +
  direct copy or set_default(). std::optional<T> and trilean are gone
  from the value class API.
- Heartbeat_period_value::load_from uses my_strtod() instead of
  my_decimal for the on-disk format. from_decimal kept for CHANGE
  MASTER.
- RocksDB #if __cplusplus < 201703L guard at the top of
  rpl_master_info_file.h dropped; header now compiles in C++11.
  cstdint dropped; uint32_t / UINT32_MAX in touched code replaced by
  MariaDB's uint32 / UINT_MAX32. include/my_global.h gains
  INT_BUFFER_SIZE next to LONGLONG_BUFFER_SIZE.
- Pointer-style throughout (T * not T &). Multi-line inline functions
  used in more than one place moved to .cc files per style.

New features:
- SHOW VARIABLES now shows the master default values.
- If there is an wrong value for a row in a master.info file the
  corresponding variable name and the value is now written to the
  error log.

Bug fixes uncovered by the refactor:
- master_ssl_verify_server_cert had a pre-existing inconsistency with
  security implications: the documented default and the Sys_var_mybool
  default are TRUE (validate the master's certificate), but the OLD
  init_ssl_config() set the per-Master_info field to FALSE on RESET
  SLAVE ALL. Concretely: after RESET SLAVE ALL followed by a bare
  CHANGE MASTER TO (no explicit MASTER_SSL_VERIFY_SERVER_CERT), the
  slave would connect with MASTER_SSL=1 enabled but with certificate
  validation silently disabled.
  Fixed by not resetting master_ssl_verify_server_cert in
  RESET SLAVE ALL;
- As some replication setups sets master_ssl_verify_server_cert= 0
  while other does not do that, the expected value used in
  check-testcase.inc "Master_SSL_Verify_Server_Cert No" does not make
  sense.  The value of this variable is now ignored by
  check-testcase.inc
- The old code would fail to read a master info file if there was a new
  variable longer than 23 characters. This is now extended to 80.
- Removed warning on RESET SLAVE that "RESET SLAVE is implicitly changing"
  the value of 'Using_Gtid' from 'No' to 'Slave_Pos'" as this change did
  not really happen. This error was given if the master could support
  GTID but the user had specified directly or indirectly to not use GTID.

Other things
- Size of mariadb (optimize build) shrunk with 1,408,009 bytes
  (Based on 'dec' from the size command)
- Size of code in sql directory did not change notable.
- Reworked Master_use_gtid_value to remember users last choice and use
  this as default when connecting to slave.
  Replace mi->using_gtid, with was a pointer to master_use_gtid, with
  two functions:
  - using_gtid() returns the current mode, for the code that needs the
    value itself (SHOW SLAVE STATUS and performance schema output,
    comparisons against CURRENT_POS and SLAVE_POS).
  - is_gtid_supported() tells whether the connection uses gtid at all.
    The many callers that compared the mode against USE_GTID_NO with
    == or != now call this function instead of testing the enum value.
 - Master_use_gtid_value::supported() did the same test as
   is_gtid_supported() and is removed
- Removed some operators in rpl_master_info_file.* that hid
  that functions was used to read and update values.

Behavior changes:
- The last used value in CHANGE MASTER for MASTER_USE_GTID will be
  remembered for future CHANGE MASTER for the same connection. This is
  true even if RESET SLAVE is called.
- If Using git is not used with change master but log_file_name, pos,
  relay_log_name or relay_log_pos is specified this is treated as
  if Using_git=NO would have been given. (Old behavior, but not
  documented).
--auto-master-use-gtid does nothing. The default value of
  master_use_gtid is by default SlavePos that will automatically
  change to NO if the master does not support GTID. This already
  handles what auto-master-use-gtid tries to do.
- CHANGE MASTER's MASTER_HEARTBEAT_PERIOD now works like other MASTER
  options:  When set to a value, this value is kept until value is
  changed or set to DEFAULT. The DEFAULT is
  @global.master_heartbeat_period if this is set as startup, if not
  then @global.slave_net_timeout/2 is used.
2026-10-16 16:56:44 +03:00

175 lines
6.3 KiB
C++

/*
Copyright (c) 2025 MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA.
*/
#ifndef RPL_INFO_FILE_H
#define RPL_INFO_FILE_H
#include <my_sys.h> // IO_CACHE, FN_REFLEN, ...
/*
Read one '\n'-terminated decimal unsigned integer from file.
Returns false on success, true on EOF / parse error / out of range.
*/
bool uint_from_chars(IO_CACHE *file, ulonglong max_value, ulonglong *result);
/* Write an unsigned integer as decimal digits (no '\n'). */
void uint_to_chars(IO_CACHE *file, ulonglong value);
/*
Common superclass of Master_info_file and Relay_log_info_file. Provides
load and save code for their MySQL line-based sections. As only
Master_info_file has a MariaDB key=value section with a mix of explicit
and DEFAULT-able values, the code for those is in Master_info_file.
Each value is an instance of an implementation of the Info_file::Value
interface. The interface uses an explicit has_value flag (in the base)
to track whether the value was explicitly set, instead of per-class
sentinels. set_default() copies the default into value so reading the
value never needs to check is_default().
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.
Multi-line method bodies live in rpl_info_file.cc.
*/
struct Info_file
{
IO_CACHE file;
/*
Persistence interface for an unspecified item.
has_value semantics:
true: the field holds an explicitly-set value (loaded from file
or assigned by code).
false: the field holds its DEFAULT (copied in by set_default()),
or has not been initialized.
*/
struct Value
{
virtual ~Value()= default;
Value(const char *name)
:variable_name(name)
{}
const char *variable_name;
bool has_value= false;
/* True if the value is the DEFAULT (i.e. has_value is false). */
bool is_default() const { return !has_value; }
/*
Copy the DEFAULT into the value field and clear has_value. Returns
true if no DEFAULT exists (i.e. the value is mandatory). Subclasses
with a DEFAULT override this to copy in their default and return
false. The return value is used only in
Master_info_file::load_from_file(), to detect a bare key=value line
whose value type has no DEFAULT (a malformed input).
*/
virtual bool set_default() { has_value= false; return true; }
/*
Set the value by reading a line from the IO and consuming the '\n'.
Sets has_value to true on success. Returns false on success,
true on error.
*/
virtual bool load_from(IO_CACHE *file)= 0;
/*
Write the value to the file without a '\n'.
This is only called in the case is_default() is false.
*/
virtual void save_to(IO_CACHE *file)= 0;
};
/* Unsigned 32-bit integer value (mandatory). */
struct Uint_value: Value
{
Uint_value(const char *name): Value(name) {}
uint value;
bool load_from(IO_CACHE *file) override;
void save_to(IO_CACHE *file) override;
};
/* Unsigned 64-bit integer value (mandatory). */
struct Ulonglong_value: Value
{
Ulonglong_value(const char *name): Value(name) {}
ulonglong value;
bool load_from(IO_CACHE *file) override;
void save_to(IO_CACHE *file) override;
};
/*
Null-terminated string value (mandatory). The buffer is owned by the
parent struct and passed in via the constructor.
*/
struct String_value: Value
{
char *buf;
size_t buf_size;
String_value(const char *name, char *buf, size_t size):
Value(name), buf(buf), buf_size(size) {}
bool load_from(IO_CACHE *file) override;
void save_to(IO_CACHE *file) override;
};
virtual ~Info_file()= default;
virtual bool load_from_file()= 0;
virtual void save_to_file()= 0;
protected:
/*
(Re)load the MySQL line-based section from the file.
@param values Array of pointers to value subobjects of *this. nullptr
marks a line to skip (MySQL-only fields MariaDB ignores).
The first element must be a String_value, to be
unambiguous with the line count line.
@param size Number of elements in values.
@param default_line_count
Some MySQL/MariaDB versions generate more lines than needed.
Starting with MySQL/MariaDB 4.1.x for Master_info_file and 5.6.x
for Relay_log_info_file, the first line is the number of value
lines, including the line count itself. This parameter specifies
the effective line count before those versions (where the first
line is a filename rather than an integer).
@return false on success, true on error.
*/
bool load_from_file(Value *const *values, size_t size,
size_t default_line_count= 0,
int value_counter_correction= 0);
/*
Flush the MySQL line-based section to the file.
@param values Array of pointers to value subobjects.
nullptr entries write an empty line.
@param size Number of elements in values.
@param total_line_count Number of lines to declare on the first line.
If larger than size, the file is padded with
empty lines. This reservation provides
compatibility with MySQL, which has added
more old-style lines.
*/
void save_to_file(Value *const *values, size_t size,
size_t total_line_count);
};
#endif