mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
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.
233 lines
6.4 KiB
C++
233 lines
6.4 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.
|
|
*/
|
|
|
|
#include "mariadb.h"
|
|
#include "rpl_info_file.h"
|
|
#include <mysqld_error.h> // Error numbers
|
|
#include <m_string.h> // strmake, int10_to_str, ll2str
|
|
|
|
|
|
bool uint_from_chars(IO_CACHE *file, ulonglong max_value, ulonglong *result)
|
|
{
|
|
int error;
|
|
longlong val;
|
|
/* The +1 is for the end \n that my_b_gets() includes */
|
|
char buf[LONGLONG_BUFFER_SIZE+1];
|
|
char *end;
|
|
size_t length;
|
|
if (!(length= my_b_gets(file, buf, sizeof(buf))))
|
|
return true;
|
|
end= buf + length;
|
|
val= my_strtoll10(buf, &end, &error);
|
|
if (error != 0 || *end != '\n' || (ulonglong) val > max_value)
|
|
return true;
|
|
*result= (ulonglong) val;
|
|
return false;
|
|
}
|
|
|
|
void uint_to_chars(IO_CACHE *file, ulonglong value)
|
|
{
|
|
char buf[LONGLONG_BUFFER_SIZE];
|
|
char *end= longlong10_to_str((longlong) value, buf, 10);
|
|
my_b_write(file, (const uchar *) buf, end - buf);
|
|
}
|
|
|
|
|
|
bool Info_file::Uint_value::load_from(IO_CACHE *file)
|
|
{
|
|
ulonglong tmp;
|
|
if (uint_from_chars(file, UINT_MAX32, &tmp))
|
|
{
|
|
set_default();
|
|
return true;
|
|
}
|
|
value= (uint) tmp;
|
|
has_value= true;
|
|
return false;
|
|
}
|
|
|
|
|
|
void Info_file::Uint_value::save_to(IO_CACHE *file)
|
|
{
|
|
uint_to_chars(file, value);
|
|
}
|
|
|
|
|
|
bool Info_file::Ulonglong_value::load_from(IO_CACHE *file)
|
|
{
|
|
if (uint_from_chars(file, ULONGLONG_MAX, &value))
|
|
{
|
|
set_default();
|
|
return true;
|
|
}
|
|
has_value= true;
|
|
return false;
|
|
}
|
|
|
|
|
|
void Info_file::Ulonglong_value::save_to(IO_CACHE *file)
|
|
{
|
|
uint_to_chars(file, value);
|
|
}
|
|
|
|
|
|
bool Info_file::String_value::load_from(IO_CACHE *file)
|
|
{
|
|
size_t length= my_b_gets(file, buf, buf_size);
|
|
if (!length)
|
|
{
|
|
set_default();
|
|
return true;
|
|
}
|
|
/* If we stopped on a newline, kill it. */
|
|
char *last_char= buf + length - 1;
|
|
if (*last_char == '\n')
|
|
{
|
|
*last_char= '\0';
|
|
has_value= true;
|
|
return false;
|
|
}
|
|
/* Consume the lost line break, or error if the line overflowed. */
|
|
if (my_b_get(file) != '\n')
|
|
{
|
|
set_default();
|
|
return true;
|
|
}
|
|
has_value= true;
|
|
return false;
|
|
}
|
|
|
|
|
|
void Info_file::String_value::save_to(IO_CACHE *file)
|
|
{
|
|
my_b_write(file, (const uchar *) buf, strlen(buf));
|
|
}
|
|
|
|
|
|
/*
|
|
Read a master.info or relay_log.info file
|
|
@param values Read fixed position values here
|
|
@param size Number of values
|
|
@param default_line_count
|
|
Number of values in old files that does not have a line
|
|
count at first line
|
|
@param value_count_correction
|
|
1 for master.info files and 0 for relay_log_files.
|
|
This is because in master.info files the line_count includes
|
|
the counter while for relay_log it does not include the
|
|
row counter
|
|
*/
|
|
|
|
bool Info_file::load_from_file(Value *const *values, size_t size,
|
|
size_t default_line_count,
|
|
int value_count_correction)
|
|
{
|
|
long val;
|
|
/*
|
|
The first row is temporarily stored in the first value. If it is a
|
|
line count and not a log name (new format), the second row will
|
|
overwrite it. The first value, instead of a temporary buffer,
|
|
to be able to use the value if there is no line count.
|
|
Note that for this to work it requires that the first real value in
|
|
the file is a string!
|
|
*/
|
|
String_value *line1= dynamic_cast<String_value *>(values[0]);
|
|
if (line1->load_from(&file))
|
|
{
|
|
my_printf_error(ER_WRONG_VALUE, "Wrong data at start of master info file",
|
|
MYF(ME_FATAL | ME_ERROR_LOG));
|
|
return true;
|
|
}
|
|
char *end= str2int(line1->buf, line1->buf_size, 10, &val);
|
|
/*
|
|
If this first line was not a number - the line count, then it was
|
|
the first value for real, so the for loop should skip over it.
|
|
*/
|
|
size_t i= !end || *end != '\0';
|
|
size_t line_count= (i ?
|
|
default_line_count :
|
|
(size_t) val - value_count_correction);
|
|
for (; i < line_count; i++)
|
|
{
|
|
int chr;
|
|
if (i < size)
|
|
{
|
|
Value *value= values[i];
|
|
if (value)
|
|
{
|
|
my_off_t filepos= my_b_tell(&file);
|
|
if (value->load_from(&file))
|
|
{
|
|
if (!(reinit_io_cache(&file, READ_CACHE, filepos, 0, 0)))
|
|
{
|
|
char buf[160];
|
|
buf[0]= 0;
|
|
size_t length= my_b_gets(&file, buf, sizeof(buf));
|
|
/* Strip the trailing '\n' that my_b_gets() includes. */
|
|
if (length && buf[length - 1] == '\n')
|
|
buf[length - 1]= '\0';
|
|
my_error(ER_WRONG_VALUE, MYF(ME_FATAL | ME_ERROR_LOG),
|
|
value->variable_name, buf);
|
|
}
|
|
return true;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
/*
|
|
Count and discard unrecognized lines. This is especially to prepare
|
|
for Master_info_file for MariaDB 10.0+, which reserves a bunch of
|
|
lines before its unique key=value section to accomodate any future
|
|
line-based (old-style) additions in MySQL.
|
|
*/
|
|
while ((chr= my_b_get(&file)) != '\n')
|
|
if (chr == my_b_EOF)
|
|
{
|
|
my_printf_error(ER_WRONG_VALUE, "Garbage at end of file",
|
|
MYF(ME_FATAL));
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void Info_file::save_to_file(Value *const *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,
|
|
we may leave trailing garbage. The garbage does not matter thanks
|
|
to the effective-line count on the first line of the file.
|
|
*/
|
|
uint_to_chars(&file, total_line_count);
|
|
my_b_write_byte(&file, '\n');
|
|
for (Value *const *value= values, * const *end= value + size;
|
|
value < end;
|
|
value++)
|
|
{
|
|
if (*value)
|
|
(*value)->save_to(&file);
|
|
my_b_write_byte(&file, '\n');
|
|
}
|
|
/* Pad additional reserved lines. */
|
|
for (; total_line_count > size; --total_line_count)
|
|
my_b_write_byte(&file, '\n');
|
|
}
|