mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
MDEV-37530 Refactor Master & Relay Log info to iterable tuples
The persistence code of CHANGE MASTER values needs to match file
lines with the formatting for the corresponding field’s type.
This is unstructured, repetitive (not DRY), and makes feature expansions
(such as MDEV-28302 `CHANGE MASTER …=DEFAULT`)
error-prone if not difficult.
This commit moves these functions and global constants from
`slave.cc`/`.h`, as well as the Master and Relay Log Info File
entries from `Rpl_mi` and `Rpl_rli`, to dedicated `rpl_*info_file.h`
files and under corresponding structs to facilitate organization.
Namely, this commit wraps those file entries with transparent
structs that inherit from a `Persistent` interface,
or shared helper structs that themselves inherit from `Persistent`.
By moving the file read/write helper functions to or behind
implementations of `Persistent`’s virtual methods,
reading or writing the file only takes a type-agnostic loop
over the (wrapped) CHANGE MASTER values.
* This commit also includes preemptive support
for preserving MDEV-28302’s `=DEFAULT`.
As such, unset fields (namely `master_connect_retry`)
now remember their `DEFAULT` states
rather than whatever the default is at CHANGE MASTER time.
* For consistency’s sake, `master_heartbeat_period` is
now reset at RESET REPLICA instead of CHANGE MASTER.
As this refactor will disconnect it from fixes for
some open bugs in prior versions, this commit also:
* Reimplements the value reader functions to be strict with their input
* Fixes MDEV-38010
number parsing ignores trailing garbage and overflows
* Supercedes MDEV-38020 integer overflow
* Changes master_heartbeat_period from a `float` of seconds
to a `uint32_t` of milliseconds (adding `/1000.0`s as needed)
* Fixes MDEV-35879 `Slave_heartbeat_period` is imprecise
* The maximum of `master_heartbeat_period` has been
increased to 4294967.295, i.e., (2³²-1)÷1000.
* `master_heartbeat_period` now rounds
instead of truncates (rounds down).
* Prepares to make `master_retry_count` 64-bit on
LLP64 (e.g., Windows) to match LP64 (e.g., Linux)
Reviewed-by: Brandon Nesterenko <brandon.nesterenko@mariadb.com>
This commit is contained in:
committed by
Sergei Golubchik
parent
8857312503
commit
89bd6b0033
@@ -57,7 +57,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
|
||||
../sql/field.cc ../sql/field_conv.cc ../sql/field_comp.cc
|
||||
../sql/filesort_utils.cc ../sql/sql_digest.cc
|
||||
../sql/filesort.cc ../sql/grant.cc
|
||||
../sql/gstream.cc ../sql/slave.cc
|
||||
../sql/gstream.cc
|
||||
../sql/signal_handler.cc
|
||||
../sql/handler.cc ../sql/hash_filo.cc ../sql/hostname.cc
|
||||
../sql/init.cc ../sql/item_buff.cc ../sql/item_cmpfunc.cc
|
||||
|
||||
@@ -22,58 +22,6 @@ set @@global.slave_net_timeout= 10;
|
||||
--enable_warnings
|
||||
|
||||
--enable_prepare_warnings
|
||||
###
|
||||
### Checking the range
|
||||
###
|
||||
|
||||
#
|
||||
# default period slave_net_timeout/2
|
||||
#
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root';
|
||||
--query_vertical show status like 'Slave_heartbeat_period';
|
||||
|
||||
#
|
||||
# the max for the period is ULONG_MAX/1000; an attempt to exceed it is denied
|
||||
#
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
--error ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE
|
||||
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 4294968;
|
||||
--query_vertical show status like 'Slave_heartbeat_period';
|
||||
|
||||
#
|
||||
# the min value for the period is 1 millisecond an attempt to assign a
|
||||
# lesser will be warned with treating the value as zero
|
||||
#
|
||||
connection slave;
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
### 5.1 mtr does not have --warning ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE
|
||||
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 0.0009999;
|
||||
--query_vertical show status like 'Slave_heartbeat_period';
|
||||
|
||||
#
|
||||
# the actual max and min must be accepted
|
||||
#
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 4294967;
|
||||
--query_vertical show status like 'Slave_heartbeat_period';
|
||||
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 0.001;
|
||||
--query_vertical show status like 'Slave_heartbeat_period';
|
||||
|
||||
reset slave;
|
||||
|
||||
#
|
||||
# A warning if period greater than slave_net_timeout
|
||||
#
|
||||
set @@global.slave_net_timeout= 5;
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root', master_heartbeat_period= 5.001;
|
||||
--query_vertical show status like 'Slave_heartbeat_period';
|
||||
|
||||
reset slave;
|
||||
|
||||
#
|
||||
# A warning if slave_net_timeout is set to less than the current HB period
|
||||
#
|
||||
|
||||
@@ -8,41 +8,6 @@ reset master;
|
||||
connection slave;
|
||||
set @restore_slave_net_timeout= @@global.slave_net_timeout;
|
||||
set @@global.slave_net_timeout= 10;
|
||||
change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root';
|
||||
show status like 'Slave_heartbeat_period';;
|
||||
Variable_name Slave_heartbeat_period
|
||||
Value 5.000
|
||||
change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 4294968;
|
||||
ERROR HY000: The requested value for the heartbeat period is either negative or exceeds the maximum allowed (4294967 seconds)
|
||||
show status like 'Slave_heartbeat_period';;
|
||||
Variable_name Slave_heartbeat_period
|
||||
Value 5.000
|
||||
connection slave;
|
||||
change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 0.0009999;
|
||||
Warnings:
|
||||
Warning 1703 The requested value for the heartbeat period is less than 1 millisecond. The value is reset to 0, meaning that heartbeating will effectively be disabled
|
||||
show status like 'Slave_heartbeat_period';;
|
||||
Variable_name Slave_heartbeat_period
|
||||
Value 0.000
|
||||
change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 4294967;
|
||||
Warnings:
|
||||
Warning 1704 The requested value for the heartbeat period exceeds the value of `slave_net_timeout' seconds. A sensible value for the period should be less than the timeout
|
||||
show status like 'Slave_heartbeat_period';;
|
||||
Variable_name Slave_heartbeat_period
|
||||
Value 4294967.000
|
||||
change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 0.001;
|
||||
show status like 'Slave_heartbeat_period';;
|
||||
Variable_name Slave_heartbeat_period
|
||||
Value 0.001
|
||||
reset slave;
|
||||
set @@global.slave_net_timeout= 5;
|
||||
change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 5.001;
|
||||
Warnings:
|
||||
Warning 1704 The requested value for the heartbeat period exceeds the value of `slave_net_timeout' seconds. A sensible value for the period should be less than the timeout
|
||||
show status like 'Slave_heartbeat_period';;
|
||||
Variable_name Slave_heartbeat_period
|
||||
Value 5.001
|
||||
reset slave;
|
||||
set @@global.slave_net_timeout= 5;
|
||||
change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root', master_heartbeat_period= 4;
|
||||
show status like 'Slave_heartbeat_period';;
|
||||
|
||||
@@ -146,7 +146,7 @@ SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period';
|
||||
Variable_name Value
|
||||
Slave_heartbeat_period 0.001
|
||||
RESET SLAVE;
|
||||
CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=0.0009;
|
||||
CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=0.00049;
|
||||
Warnings:
|
||||
Warning 1703 The requested value for the heartbeat period is less than 1 millisecond. The value is reset to 0, meaning that heartbeating will effectively be disabled
|
||||
SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period';
|
||||
@@ -155,21 +155,21 @@ Slave_heartbeat_period 0.000
|
||||
RESET SLAVE;
|
||||
|
||||
*** Max slave_heartbeat_timeout ***
|
||||
CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=4294967;
|
||||
CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=4294967.295;
|
||||
Warnings:
|
||||
Warning 1704 The requested value for the heartbeat period exceeds the value of `slave_net_timeout' seconds. A sensible value for the period should be less than the timeout
|
||||
SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period';
|
||||
Variable_name Value
|
||||
Slave_heartbeat_period 4294967.000
|
||||
Slave_heartbeat_period 4294967.295
|
||||
RESET SLAVE;
|
||||
CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=4294968;
|
||||
ERROR HY000: The requested value for the heartbeat period is either negative or exceeds the maximum allowed (4294967 seconds)
|
||||
ERROR HY000: The requested value for the heartbeat period is either negative or exceeds the maximum allowed (4294967.295 seconds)
|
||||
RESET SLAVE;
|
||||
CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=8589935;
|
||||
ERROR HY000: The requested value for the heartbeat period is either negative or exceeds the maximum allowed (4294967 seconds)
|
||||
ERROR HY000: The requested value for the heartbeat period is either negative or exceeds the maximum allowed (4294967.295 seconds)
|
||||
RESET SLAVE;
|
||||
CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=MASTER_PORT, MASTER_USER='root', MASTER_CONNECT_RETRY=20, MASTER_HEARTBEAT_PERIOD=4294967296;
|
||||
ERROR HY000: The requested value for the heartbeat period is either negative or exceeds the maximum allowed (4294967 seconds)
|
||||
ERROR HY000: The requested value for the heartbeat period is either negative or exceeds the maximum allowed (4294967.295 seconds)
|
||||
RESET SLAVE;
|
||||
|
||||
*** Misc incorrect values ***
|
||||
|
||||
@@ -6,7 +6,7 @@ set @restore_slave_net_timeout= @@global.slave_net_timeout;
|
||||
set @@global.slave_net_timeout= 10;
|
||||
show status like 'Slave_heartbeat_period';;
|
||||
Variable_name Slave_heartbeat_period
|
||||
Value 60.000
|
||||
Value 5.000
|
||||
SET @saved_dbug= @@GLOBAL.debug_dbug;
|
||||
SET GLOBAL debug_dbug="+d,simulate_slave_heartbeat_network_error";
|
||||
include/start_slave.inc
|
||||
|
||||
@@ -198,14 +198,14 @@ eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTE
|
||||
SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period';
|
||||
RESET SLAVE;
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.0009;
|
||||
eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=0.00049;
|
||||
SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period';
|
||||
RESET SLAVE;
|
||||
--echo
|
||||
|
||||
--echo *** Max slave_heartbeat_timeout ***
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=4294967;
|
||||
eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$MASTER_MYPORT, MASTER_USER='root', MASTER_CONNECT_RETRY=$connect_retry, MASTER_HEARTBEAT_PERIOD=4294967.295;
|
||||
SHOW GLOBAL STATUS LIKE 'slave_heartbeat_period';
|
||||
RESET SLAVE;
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
|
||||
@@ -39,7 +39,7 @@ start slave;
|
||||
chmod 0600 $MYSQLD_SLAVE_DATADIR/master.info;
|
||||
# It will fail again because the file is empty so the slave cannot get valuable
|
||||
# info about how to connect to the master from it (failure in
|
||||
# init_strvar_from_file() in init_master_info()).
|
||||
# InfoFile::Persistent::load_from() in init_master_info()).
|
||||
--error 1201
|
||||
start slave;
|
||||
--replace_result $MASTER_MYPORT MASTER_PORT
|
||||
|
||||
@@ -790,7 +790,6 @@ File_parser_dummy_hook file_parser_dummy_hook;
|
||||
|
||||
/* replication parameters */
|
||||
uint report_port= 0;
|
||||
ulong master_retry_count=100000;
|
||||
char *master_info_file;
|
||||
char *relay_log_info_file, *report_user, *report_password, *report_host;
|
||||
char *opt_relay_logname = 0, *opt_relaylog_index_name=0;
|
||||
@@ -7013,11 +7012,11 @@ struct my_option my_long_options[]=
|
||||
"more than one storage engine, when binary log is disabled)",
|
||||
&opt_tc_log_file, &opt_tc_log_file, 0, GET_STR,
|
||||
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#ifdef HAVE_REPLICATION
|
||||
{"master-retry-count", 0,
|
||||
"The number of tries the slave will make to connect to the master before giving up",
|
||||
&master_retry_count, &master_retry_count, 0, GET_ULONG,
|
||||
&master_retry_count, &master_retry_count, 0, GET_ULL,
|
||||
REQUIRED_ARG, static_cast<longlong>(master_retry_count), 0, 0, 0, 0, 0},
|
||||
#ifdef HAVE_REPLICATION
|
||||
{"init-rpl-role", 0, "Set the replication role",
|
||||
&rpl_status, &rpl_status, &rpl_role_typelib,
|
||||
GET_ENUM, REQUIRED_ARG, RPL_AUTH_MASTER, 0, 0, 0, 0, 0},
|
||||
@@ -7307,7 +7306,8 @@ static int show_heartbeat_period(THD *thd, SHOW_VAR *var, void *buff,
|
||||
get_master_info(&thd->variables.default_master_connection,
|
||||
Sql_condition::WARN_LEVEL_NOTE))
|
||||
{
|
||||
sprintf(static_cast<char*>(buff), "%.3f", mi->heartbeat_period);
|
||||
sprintf(static_cast<char*>(buff), "%.3lf",
|
||||
mi->master_heartbeat_period/1000.0);
|
||||
mi->release();
|
||||
var->type= SHOW_CHAR;
|
||||
var->value= buff;
|
||||
|
||||
336
sql/rpl_info_file.h
Normal file
336
sql/rpl_info_file.h
Normal file
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
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 <cstdint> // uintN_t
|
||||
#include <charconv> // std::from/to_chars and other helpers
|
||||
#include <functional> // superclass of Info_file::Mem_fn
|
||||
#include <my_sys.h> // IO_CACHE, FN_REFLEN, ...
|
||||
|
||||
|
||||
/** Helpers for reading and writing integers to and from @ref IO_CACHE
|
||||
TODO: Other components, if you find these useful,
|
||||
feel free to move these out of this Replication module.
|
||||
*/
|
||||
namespace Int_IO_CACHE
|
||||
{
|
||||
/** Number of fully-utilized decimal digits plus
|
||||
* the partially-utilized digit (e.g., the 2's place in "2147483647")
|
||||
* The sign, if signed (:
|
||||
*/
|
||||
template<typename I> static constexpr size_t BUF_SIZE=
|
||||
std::numeric_limits<I>::digits10 + 1 + std::numeric_limits<I>::is_signed;
|
||||
static constexpr auto ERRC_OK= std::errc();
|
||||
|
||||
/**
|
||||
@ref IO_CACHE (reading one line with the `\n`) version of std::from_chars()
|
||||
@tparam I integer type
|
||||
@return `false` if the line has parsed successfully or `true` if error
|
||||
*/
|
||||
template<typename I> static bool from_chars(IO_CACHE *file, I &value)
|
||||
{
|
||||
/**
|
||||
+2 for the terminating `\n\0` (They are ignored by
|
||||
std::from_chars(), but my_b_gets() includes them.)
|
||||
*/
|
||||
char buf[BUF_SIZE<I> + 2];
|
||||
/// includes the `\n` but excludes the `\0`
|
||||
size_t length= my_b_gets(file, buf, sizeof(buf));
|
||||
if (!length) // EOF
|
||||
return true;
|
||||
// SFINAE if `I` is not a numeric type
|
||||
std::from_chars_result result= std::from_chars(buf, &(buf[length]), value);
|
||||
// Return `true` if the conversion failed or if the number ended early
|
||||
return result.ec != ERRC_OK || *(result.ptr) != '\n';
|
||||
}
|
||||
/**
|
||||
Convenience overload of from_chars(IO_CACHE *, I &) for `operator=` types
|
||||
@tparam I inner integer type
|
||||
@tparam T wrapper type
|
||||
*/
|
||||
template<typename I, class T> static bool from_chars(IO_CACHE *file, T *self)
|
||||
{
|
||||
I value;
|
||||
if (from_chars(file, value))
|
||||
return true;
|
||||
(*self)= value;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ref IO_CACHE (writing *without* a `\n`) version of std::to_chars()
|
||||
@tparam I (inner) integer type
|
||||
*/
|
||||
template<typename I> static void to_chars(IO_CACHE *file, I value)
|
||||
{
|
||||
/**
|
||||
my_b_printf() uses a buffer too,
|
||||
so we might as well save on format parsing and buffer resizing
|
||||
*/
|
||||
char buf[BUF_SIZE<I>];
|
||||
std::to_chars_result result= std::to_chars(buf, &buf[sizeof(buf)], value);
|
||||
DBUG_ASSERT(result.ec == ERRC_OK);
|
||||
my_b_write(file, reinterpret_cast<const uchar *>(buf), result.ptr - buf);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
This common superclass of @ref Master_info_file and
|
||||
@ref Relay_log_info_file provides them common code for saving
|
||||
and loading values in their MySQL line-based sections.
|
||||
As only the @ref Master_info_file has a MariaDB `key=value`
|
||||
section with a mix of explicit and `DEFAULT`-able values,
|
||||
code for those are in @ref Master_info_file instead.
|
||||
|
||||
Each value is an instance of an implementation of the
|
||||
@ref Info_file::Persistent interface. For convenience, they also have
|
||||
assignment and implicit conversion operators for their underlying types.
|
||||
|
||||
C++ templates enables code reuse for those implementation structs, but
|
||||
templates are not suitable for the conventional header/implementation split.
|
||||
Thus, this and derived files are header-only units (methods are `inline`).
|
||||
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.
|
||||
*/
|
||||
struct Info_file
|
||||
{
|
||||
IO_CACHE file;
|
||||
|
||||
|
||||
/// Persistence interface for an unspecified item
|
||||
struct Persistent
|
||||
{
|
||||
virtual ~Persistent()= default;
|
||||
// for save_to_file()
|
||||
virtual bool is_default() { return false; }
|
||||
/// @return `true` if the item is mandatory and couldn't provide a default
|
||||
virtual bool set_default() { return true; }
|
||||
/** set the value by reading a line from the IO and consume the `\n`
|
||||
@return `false` if the line has parsed successfully or `true` if error
|
||||
@post is_default() is `false`
|
||||
*/
|
||||
virtual bool load_from(IO_CACHE *file)= 0;
|
||||
/** write the *effective* value to the IO **without** a `\n`
|
||||
(The caller will separately determine how
|
||||
to represent using the default value.)
|
||||
*/
|
||||
virtual void save_to(IO_CACHE *file)= 0;
|
||||
};
|
||||
|
||||
/** Integer Value
|
||||
@tparam I signed or unsigned integer type
|
||||
@see Master_info_file::Optional_int_value
|
||||
version with `DEFAULT` (not a subclass)
|
||||
*/
|
||||
template<typename I> struct Int_value: Persistent
|
||||
{
|
||||
I value;
|
||||
operator I() { return value; }
|
||||
auto &operator=(I value)
|
||||
{
|
||||
this->value= value;
|
||||
return *this;
|
||||
}
|
||||
virtual bool load_from(IO_CACHE *file) override
|
||||
{ return Int_IO_CACHE::from_chars(file, value); }
|
||||
virtual void save_to(IO_CACHE *file) override
|
||||
{ return Int_IO_CACHE::to_chars(file, value); }
|
||||
};
|
||||
|
||||
/// Null-Terminated String (usually file name) Value
|
||||
template<size_t size= FN_REFLEN> struct String_value: Persistent
|
||||
{
|
||||
char buf[size];
|
||||
/**
|
||||
Reads should consider this an immutable '\0'-terminated string (especially
|
||||
with @ref Optional_path_value where a `DEFAULT` may substitute the value).
|
||||
Writes may prefers to directly address the underlying @ref buf.
|
||||
*/
|
||||
virtual operator const char *() { return buf; }
|
||||
/// @param other non-`nullptr` `\0`-terminated string
|
||||
auto &operator=(const char *other)
|
||||
{
|
||||
strmake(buf, other, size-1);
|
||||
return *this;
|
||||
}
|
||||
virtual bool load_from(IO_CACHE *file) override
|
||||
{
|
||||
size_t length= my_b_gets(file, buf, size);
|
||||
if (!length) // EOF
|
||||
return true;
|
||||
/// If we stopped on a newline, kill it.
|
||||
char &last_char= buf[length-1];
|
||||
if (last_char == '\n')
|
||||
{
|
||||
last_char= '\0';
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
Consume the lost line break,
|
||||
or error if the line overflows the @ref buf.
|
||||
*/
|
||||
return my_b_get(file) != '\n';
|
||||
}
|
||||
virtual void save_to(IO_CACHE *file) override
|
||||
{
|
||||
const char *buf= *this;
|
||||
my_b_write(file, reinterpret_cast<const uchar *>(buf), strlen(buf));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
virtual ~Info_file()= default;
|
||||
virtual bool load_from_file()= 0;
|
||||
virtual void save_to_file()= 0;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
std::Mem_fn()-like nullable replacement for
|
||||
[member pointer upcasting](https://wg21.link/P0149R3)
|
||||
*/
|
||||
struct Mem_fn: std::function<Persistent &(Info_file *self)>
|
||||
{
|
||||
using List= const std::initializer_list<Mem_fn>;
|
||||
/// Null Constructor
|
||||
Mem_fn(std::nullptr_t null= nullptr):
|
||||
std::function<Persistent &(Info_file *)>(null) {}
|
||||
/** Non-Null Constructor
|
||||
@tparam T CRTP subclass of Info_file
|
||||
@tparam M @ref Persistent subclass of the member
|
||||
@param pm member pointer
|
||||
*/
|
||||
template<class T, typename M> Mem_fn(M T::* pm):
|
||||
std::function<Persistent &(Info_file *)>(
|
||||
[pm](Info_file *self) -> Persistent &
|
||||
{ return self->*static_cast<M Info_file::*>(pm); }
|
||||
) {}
|
||||
};
|
||||
|
||||
/**
|
||||
(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.
|
||||
@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.
|
||||
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),
|
||||
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
|
||||
*/
|
||||
bool load_from_file(Mem_fn::List value_list, size_t default_line_count)
|
||||
{
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
auto &line1= dynamic_cast<String_value<> &>((*(value_list.begin()))(this));
|
||||
if (line1.load_from(&file))
|
||||
return true;
|
||||
size_t line_count;
|
||||
std::from_chars_result result= std::from_chars(
|
||||
line1.buf, &line1.buf[sizeof(line1.buf)], line_count);
|
||||
/**
|
||||
If this first line was not a number - the line count,
|
||||
then it was the first value for real,
|
||||
so the for loop should then skip over it, the index 0 of the list.
|
||||
*/
|
||||
size_t i= result.ec != Int_IO_CACHE::ERRC_OK || *(result.ptr) != '\0';
|
||||
/*
|
||||
Set the default after parsing: While std::from_chars() does not replace
|
||||
the output if it failed, it does replace if the line is not fully spent.
|
||||
*/
|
||||
if (i)
|
||||
line_count= default_line_count;
|
||||
for (; i < line_count; ++i)
|
||||
{
|
||||
int c;
|
||||
if (i < value_list.size()) // line known in the `value_list`
|
||||
{
|
||||
const Mem_fn &pm= value_list.begin()[i];
|
||||
if (pm)
|
||||
{
|
||||
if (pm(this).load_from(&file))
|
||||
return true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/*
|
||||
Count and discard unrecognized lines.
|
||||
This is especially to prepare for @ref 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.
|
||||
(This will make moving from MariaDB to MySQL easier by not
|
||||
requiring MySQL to recognize MariaDB `key=value` lines.)
|
||||
*/
|
||||
while ((c= my_b_get(&file)) != '\n')
|
||||
if (c == my_b_EOF)
|
||||
return true; // EOF already?
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
Flush the MySQL line-based section to the @ref 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.
|
||||
*/
|
||||
void save_to_file(Mem_fn::List value_list, size_t total_line_count)
|
||||
{
|
||||
DBUG_ASSERT(total_line_count > value_list.size());
|
||||
my_b_seek(&file, 0);
|
||||
/*
|
||||
If the new contents take less space than the previous file contents,
|
||||
then this code would write the file with unerased trailing garbage lines.
|
||||
But these garbage don't matter thanks to the number
|
||||
of effective lines in the first line of the file.
|
||||
*/
|
||||
Int_IO_CACHE::to_chars(&file, total_line_count);
|
||||
my_b_write_byte(&file, '\n');
|
||||
for (const Mem_fn &pm: value_list)
|
||||
{
|
||||
if (pm)
|
||||
pm(this).save_to(&file);
|
||||
my_b_write_byte(&file, '\n');
|
||||
}
|
||||
/*
|
||||
Pad additional reserved lines:
|
||||
(1 for the line count line + line count) inclusive -> max line inclusive
|
||||
= line count exclusive <- max line inclusive
|
||||
*/
|
||||
for (; total_line_count > value_list.size(); --total_line_count)
|
||||
my_b_write_byte(&file, '\n');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
717
sql/rpl_master_info_file.h
Normal file
717
sql/rpl_master_info_file.h
Normal file
@@ -0,0 +1,717 @@
|
||||
/*
|
||||
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_MASTER_INFO_FILE_H
|
||||
#define RPL_MASTER_INFO_FILE_H
|
||||
|
||||
#include "rpl_info_file.h"
|
||||
#include <unordered_map> // Type of Master_info_file::VALUE_MAP
|
||||
#include <string_view> // Key type of Master_info_file::VALUE_MAP
|
||||
#include <optional> // Storage type of Master_info_file::Optional_int_value
|
||||
#include <unordered_set> // Used by Master_info_file::load_from_file() to dedup
|
||||
#include "sql_const.h" // MAX_PASSWORD_LENGTH
|
||||
// Interface type of Master_info_file::master_heartbeat_period
|
||||
#include "my_decimal.h"
|
||||
|
||||
|
||||
/**
|
||||
A three-way comparison function for using
|
||||
sort_dynamic() and bsearch() on ID_array_value::array.
|
||||
@return -1 if first argument is less, 0 if it equal to, or 1 if it is greater
|
||||
than the second
|
||||
@deprecated Use a sorted set, such as @ref std::set,
|
||||
to save on explicitly calling those functions.
|
||||
*/
|
||||
inline static int change_master_id_cmp(const void *arg1, const void *arg2)
|
||||
{
|
||||
const ulong &id1= *(const ulong *)arg1, &id2= *(const ulong *)arg2;
|
||||
return (id1 > id2) - (id1 < id2);
|
||||
}
|
||||
|
||||
/// enum for @ref Master_info_file::Optional_bool_value
|
||||
/*TODO:
|
||||
`UNKNOWN` is the general term in ternary logic, but this name is `#define`d in
|
||||
`item_cmpfunc.h`, which is used by target RocksDB, whose *C++11* requirement
|
||||
doesn't recognize `inline` constants (whereas the server is on C++17).
|
||||
*/
|
||||
enum struct trilean { NO, YES, DEFAULT= -1 };
|
||||
/// enum for @ref Master_info_file::master_use_gtid
|
||||
enum struct enum_master_use_gtid { NO, CURRENT_POS, SLAVE_POS, DEFAULT };
|
||||
/// String names for non-@ref enum_master_use_gtid::DEFAULT values
|
||||
inline const char *master_use_gtid_names[]=
|
||||
{"No", "Current_Pos", "Slave_Pos", nullptr};
|
||||
|
||||
/**
|
||||
`mariadbd` Options for the `DEFAULT` values of @ref Master_info_file values
|
||||
@{
|
||||
*/
|
||||
/// Computes the `DEFAULT` value of @ref ::master_heartbeat_period
|
||||
extern uint slave_net_timeout;
|
||||
inline uint32_t master_connect_retry= 60;
|
||||
inline std::optional<uint32_t> master_heartbeat_period= std::nullopt;
|
||||
inline bool master_ssl= true;
|
||||
inline const char *master_ssl_ca = "";
|
||||
inline const char *master_ssl_capath = "";
|
||||
inline const char *master_ssl_cert = "";
|
||||
inline const char *master_ssl_crl = "";
|
||||
inline const char *master_ssl_crlpath= "";
|
||||
inline const char *master_ssl_key = "";
|
||||
inline const char *master_ssl_cipher = "";
|
||||
inline bool master_ssl_verify_server_cert= true;
|
||||
/// `ulong` is the data type `my_getopt` expects.
|
||||
inline auto master_use_gtid= static_cast<ulong>(enum_master_use_gtid::DEFAULT);
|
||||
inline uint64_t master_retry_count= 100'000;
|
||||
/// }@
|
||||
|
||||
|
||||
struct Master_info_file: Info_file
|
||||
{
|
||||
|
||||
/** General Optional Value
|
||||
@tparam T wrapped type
|
||||
*/
|
||||
template<typename T> struct Optional_value: Persistent
|
||||
{
|
||||
std::optional<T> optional;
|
||||
virtual operator T()= 0;
|
||||
/// Fowards to @ref optional perfectly
|
||||
template<typename O> auto &operator=(O&& other)
|
||||
{
|
||||
optional= std::forward<O>(other);
|
||||
return *this;
|
||||
}
|
||||
bool is_default() override { return !optional.has_value(); }
|
||||
bool set_default() override
|
||||
{
|
||||
optional.reset();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
/** Integer Value with `DEFAULT`
|
||||
@tparam mariadbd_option
|
||||
server options variable that determines the value of `DEFAULT`
|
||||
@tparam I integer type (auto-deduced from `mariadbd_option`)
|
||||
@see Int_value version without `DEFAULT` (not a superclass)
|
||||
*/
|
||||
template<auto &mariadbd_option,
|
||||
typename I= std::remove_reference_t<decltype(mariadbd_option)>>
|
||||
struct Optional_int_value: Optional_value<I>
|
||||
{
|
||||
using Optional_value<I>::operator=;
|
||||
operator I() override
|
||||
{ return Optional_value<I>::optional.value_or(mariadbd_option); }
|
||||
virtual bool load_from(IO_CACHE *file) override
|
||||
{ return Int_IO_CACHE::from_chars<I>(file, this); }
|
||||
virtual void save_to(IO_CACHE *file) override
|
||||
{ return Int_IO_CACHE::to_chars(file, operator I()); }
|
||||
};
|
||||
|
||||
/**
|
||||
Optional Path Value (for SSL): @ref FN_REFLEN-sized '\0'-
|
||||
terminated string with a `mariadbd` option for the `DEFAULT`.
|
||||
@note This reuses the @ref String_value::buf to track the `DEFAULT`ed state,
|
||||
which is a bit more efficient and convenient than
|
||||
`std::optional<std::array<char, FN_REFLEN>>`.
|
||||
Specifically, when the strlen() is 0, the value is an empty string if
|
||||
the index 1 char is also '\0', or is set_default() if it is '\1'.
|
||||
*/
|
||||
template<const char *&mariadbd_option>
|
||||
struct Optional_path_value: String_value<>
|
||||
{
|
||||
operator const char *() override
|
||||
{
|
||||
if (is_default())
|
||||
return mariadbd_option;
|
||||
return String_value<>::operator const char *();
|
||||
}
|
||||
/// @param other `\0`-terminated string, or `nullptr` to call set_default()
|
||||
auto &operator=(const char *other)
|
||||
{
|
||||
if (other)
|
||||
{
|
||||
buf[1]= false; // not default
|
||||
String_value<>::operator=(other);
|
||||
}
|
||||
else
|
||||
set_default();
|
||||
return *this;
|
||||
}
|
||||
bool is_default() override { return /* strlen() == 0 */ !buf[0] && buf[1]; }
|
||||
bool set_default() override
|
||||
{
|
||||
buf[0]= false;
|
||||
buf[1]= true;
|
||||
return false;
|
||||
}
|
||||
bool load_from(IO_CACHE *file) override
|
||||
{
|
||||
buf[1]= false; // not default
|
||||
return String_value<>::load_from(file);
|
||||
}
|
||||
};
|
||||
|
||||
/** Boolean Value with `DEFAULT`.
|
||||
@note
|
||||
* This uses the @ref trilean enum,
|
||||
which is more efficient than `std::optional<bool>`.
|
||||
* load_from() and save_to() are also engineered
|
||||
to make use of the range of only two cases.
|
||||
*/
|
||||
template<bool &mariadbd_option> struct Optional_bool_value: Persistent
|
||||
{
|
||||
trilean value;
|
||||
operator bool()
|
||||
{ return is_default() ? mariadbd_option : (value != trilean::NO); }
|
||||
bool is_default() override { return value <= trilean::DEFAULT; }
|
||||
bool set_default() override
|
||||
{
|
||||
value= trilean::DEFAULT;
|
||||
return false;
|
||||
}
|
||||
auto &operator=(trilean other)
|
||||
{
|
||||
this->value= other;
|
||||
return *this;
|
||||
}
|
||||
auto &operator=(bool value)
|
||||
{ return operator=(value ? trilean::YES : trilean::NO); }
|
||||
/// @return `true` if the line is `0` or `1`, `false` otherwise or on error
|
||||
bool load_from(IO_CACHE *file) override
|
||||
{
|
||||
/** Only three chars are required:
|
||||
* One digit
|
||||
(When base prefixes are not recognized in integer parsing,
|
||||
anything with a leading `0` stops parsing
|
||||
after converting the `0` to zero anyway.)
|
||||
* the terminating `\n\0` as in IntegerLike::from_chars(IO_CACHE *, I &)
|
||||
*/
|
||||
char buf[3];
|
||||
if (my_b_gets(file, buf, 3) && buf[1] == '\n')
|
||||
switch (buf[0]) {
|
||||
case '0':
|
||||
value= trilean::NO;
|
||||
return false;
|
||||
case '1':
|
||||
value= trilean::YES;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void save_to(IO_CACHE *file) override
|
||||
{ my_b_write_byte(file, operator bool() ? '1' : '0'); }
|
||||
};
|
||||
|
||||
|
||||
/** @ref uint32_t Array value
|
||||
@deprecated
|
||||
Only one of `DO_DOMAIN_IDS` and `IGNORE_DOMAIN_IDS` can be active
|
||||
at a time, so giving them separate arrays, let alone value instances,
|
||||
is wasteful. Until we refactor this pair, this will only reference
|
||||
to existing arrays to reduce changes that will be obsolete by then.
|
||||
As references, the struct does not manage (construct/destruct) the array.
|
||||
*/
|
||||
struct ID_array_value: Persistent
|
||||
{
|
||||
/// Array of `long`s (FIXME: Domain and Server IDs should be `uint32_t`s.)
|
||||
DYNAMIC_ARRAY &array;
|
||||
ID_array_value(DYNAMIC_ARRAY &array): array(array) {}
|
||||
operator DYNAMIC_ARRAY &() { return array; }
|
||||
/// @pre @ref array is initialized
|
||||
|
||||
bool load_from(IO_CACHE *file) override
|
||||
{
|
||||
uint32_t count;
|
||||
size_t i;
|
||||
/// +1 for the terminating delimiter
|
||||
char buf[Int_IO_CACHE::BUF_SIZE<uint32_t> + 1];
|
||||
for (i= 0; i < sizeof(buf); ++i)
|
||||
{
|
||||
int c= my_b_get(file);
|
||||
if (c == my_b_EOF)
|
||||
return true;
|
||||
buf[i]= static_cast<char>(c);
|
||||
if (c == /* End of Line */ '\n' || c == /* End of Count */ ' ')
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* std::from_chars() fails if `count` will overflow in any way.
|
||||
* exclusive end index of the string = size
|
||||
*/
|
||||
std::from_chars_result result= std::from_chars(buf, &buf[i], count);
|
||||
// Reserve enough elements ahead of time.
|
||||
if (result.ec != Int_IO_CACHE::ERRC_OK || allocate_dynamic(&array, count))
|
||||
return true;
|
||||
while (count--)
|
||||
{
|
||||
uint32_t value;
|
||||
/*
|
||||
Check that the previous number ended with a ` `,
|
||||
not `\n` or anything else.
|
||||
*/
|
||||
if (*(result.ptr) != ' ')
|
||||
return true;
|
||||
for (i= 0; i < sizeof(buf); ++i)
|
||||
{
|
||||
/*
|
||||
Bottlenecks from repeated IO does not affect the
|
||||
performance of reading char by char thanks to the cache.
|
||||
*/
|
||||
int c= my_b_get(file);
|
||||
if (c == my_b_EOF)
|
||||
return true;
|
||||
buf[i]= static_cast<char>(c);
|
||||
if (c == /* End of Count */ ' ' || c == /* End of Line */ '\n')
|
||||
break;
|
||||
}
|
||||
result= std::from_chars(buf, &buf[i], value);
|
||||
if (result.ec != Int_IO_CACHE::ERRC_OK)
|
||||
return true;
|
||||
ulong id= value;
|
||||
bool oom= insert_dynamic(&array, (uchar *)&id);
|
||||
/*
|
||||
This should not error because enough
|
||||
memory was already allocate_dynamic()-ed.
|
||||
*/
|
||||
DBUG_ASSERT(!oom);
|
||||
if (oom)
|
||||
return true;
|
||||
}
|
||||
// Check that the last number ended with a `\n`, not ` ` or anything else.
|
||||
if (*(result.ptr) != '\n')
|
||||
return true;
|
||||
sort_dynamic(&array, change_master_id_cmp); // to be safe
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Store the total number of elements followed by the individual elements.
|
||||
void save_to(IO_CACHE *file) override
|
||||
{
|
||||
Int_IO_CACHE::to_chars(file, array.elements);
|
||||
for (size_t i= 0; i < array.elements; ++i)
|
||||
{
|
||||
ulong id;
|
||||
get_dynamic(&array, &id, i);
|
||||
my_b_write_byte(file, ' ');
|
||||
Int_IO_CACHE::to_chars(file, id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
`@@master_info_file` values, in SHOW SLAVE STATUS order where applicable
|
||||
@{
|
||||
*/
|
||||
|
||||
String_value<HOSTNAME_LENGTH*SYSTEM_CHARSET_MBMAXLEN + 1> master_host;
|
||||
String_value<USERNAME_LENGTH + 1> master_user;
|
||||
// Not in SHOW SLAVE STATUS
|
||||
String_value<MAX_PASSWORD_LENGTH*SYSTEM_CHARSET_MBMAXLEN + 1> master_password;
|
||||
Int_value<uint32_t> master_port;
|
||||
/// Connect_Retry
|
||||
Optional_int_value<::master_connect_retry> master_connect_retry;
|
||||
String_value<> master_log_file;
|
||||
/// Read_Master_Log_Pos
|
||||
Int_value<my_off_t> master_log_pos;
|
||||
/// Master_SSL_Allowed
|
||||
Optional_bool_value<::master_ssl> master_ssl;
|
||||
/// Master_SSL_CA_File
|
||||
Optional_path_value<::master_ssl_ca> master_ssl_ca;
|
||||
/// Master_SSL_CA_Path
|
||||
Optional_path_value<::master_ssl_capath> master_ssl_capath;
|
||||
Optional_path_value<::master_ssl_cert> master_ssl_cert;
|
||||
Optional_path_value<::master_ssl_cipher> master_ssl_cipher;
|
||||
Optional_path_value<::master_ssl_key> master_ssl_key;
|
||||
Optional_bool_value<::master_ssl_verify_server_cert>
|
||||
master_ssl_verify_server_cert;
|
||||
/// Replicate_Ignore_Server_Ids
|
||||
ID_array_value ignore_server_ids;
|
||||
Optional_path_value<::master_ssl_crl> master_ssl_crl;
|
||||
Optional_path_value<::master_ssl_crlpath> master_ssl_crlpath;
|
||||
|
||||
/** Singleton class of @ref Master_info_file::master_use_gtid:
|
||||
It is a @ref enum_master_use_gtid value
|
||||
with a `DEFAULT` value of @ref ::master_use_gtid,
|
||||
which in turn has a `DEFAULT` value based on @ref gtid_supported.
|
||||
*/
|
||||
struct: Persistent
|
||||
{
|
||||
enum_master_use_gtid mode;
|
||||
/**
|
||||
The default `master_use_gtid` is normally `SLAVE_POS`; however, if the
|
||||
master does not supports GTIDs, we fall back to `NO`. This value caches
|
||||
the check so future RESET SLAVE commands don't revert to `SLAVE_POS`.
|
||||
load_from() and save_to() are engineered (that is, hard-coded)
|
||||
on the single-digit range of @ref enum_master_use_gtid,
|
||||
similar to Optional_bool_value.
|
||||
*/
|
||||
bool gtid_supported= true;
|
||||
operator enum_master_use_gtid()
|
||||
{
|
||||
if (is_default())
|
||||
{
|
||||
auto default_use_gtid=
|
||||
static_cast<enum_master_use_gtid>(::master_use_gtid);
|
||||
return default_use_gtid >= enum_master_use_gtid::DEFAULT ? (
|
||||
gtid_supported ?
|
||||
enum_master_use_gtid::SLAVE_POS : enum_master_use_gtid::NO
|
||||
) : default_use_gtid;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
operator bool()
|
||||
{ return operator enum_master_use_gtid() != enum_master_use_gtid::NO; }
|
||||
auto &operator=(enum_master_use_gtid mode)
|
||||
{
|
||||
this->mode= mode;
|
||||
return *this;
|
||||
}
|
||||
bool is_default() override
|
||||
{ return mode >= enum_master_use_gtid::DEFAULT; }
|
||||
bool set_default() override
|
||||
{
|
||||
mode= enum_master_use_gtid::DEFAULT;
|
||||
return false;
|
||||
}
|
||||
/** @return
|
||||
`true` if the line is a @ref enum_master_use_gtid,
|
||||
`false` otherwise or on error
|
||||
*/
|
||||
bool load_from(IO_CACHE *file) override
|
||||
{
|
||||
/**
|
||||
Only 3 chars are required for the enum,
|
||||
similar to @ref Optional_bool_value::load_from()
|
||||
*/
|
||||
char buf[3];
|
||||
if (!my_b_gets(file, buf, 3) ||
|
||||
buf[1] != '\n' ||
|
||||
buf[0] > /* SLAVE_POS */ '2' || buf[0] < /* NO */ '0')
|
||||
return true;
|
||||
operator=(static_cast<enum_master_use_gtid>(buf[0] - '0'));
|
||||
return false;
|
||||
}
|
||||
void save_to(IO_CACHE *file) override
|
||||
{
|
||||
my_b_write_byte(file,
|
||||
'0' + static_cast<unsigned char>(operator enum_master_use_gtid()));
|
||||
}
|
||||
}
|
||||
/// Using_Gtid
|
||||
master_use_gtid;
|
||||
|
||||
/// Replicate_Do_Domain_Ids
|
||||
ID_array_value do_domain_ids;
|
||||
/// Replicate_Ignore_Domain_Ids
|
||||
ID_array_value ignore_domain_ids;
|
||||
Optional_int_value<::master_retry_count> master_retry_count;
|
||||
|
||||
/** Singleton class of Master_info_file::master_heartbeat_period:
|
||||
It is a non-negative `DECIMAL(10,3)` seconds value internally
|
||||
calculated as an unsigned integer milliseconds value.
|
||||
It has a `DEFAULT` value of @ref ::master_heartbeat_period,
|
||||
which in turn has a `DEFAULT` value of `@@slave_net_timeout / 2` seconds.
|
||||
*/
|
||||
struct Heartbeat_period_value: Optional_value<uint32_t>
|
||||
{
|
||||
/**
|
||||
@return std::numeric_limits<uint32_t>::max() / 1000.0
|
||||
as a constant '\0'-terminated string
|
||||
*/
|
||||
static constexpr char MAX[]= "4294967.295";
|
||||
using Optional_value::operator=;
|
||||
operator uint32_t() override
|
||||
{
|
||||
return is_default() ? ::master_heartbeat_period.value_or(
|
||||
MY_MIN(slave_net_timeout*500ULL, std::numeric_limits<uint32_t>::max())
|
||||
) : *(Optional_value<uint32_t>::optional);
|
||||
}
|
||||
/** Load from a `DECIMAL(10,3)`
|
||||
@param overprecise
|
||||
set to `true` if the decimal has more than 3 decimal digits
|
||||
@return whether the decimal is out of range
|
||||
@post Output arguments are not changed if the decimal is out of range.
|
||||
*/
|
||||
static uint from_decimal(
|
||||
uint32_t &result, const decimal_t &decimal, bool &overprecise
|
||||
)
|
||||
{
|
||||
/// Wrapper to enable only-once static const construction
|
||||
struct Decimal_from_str: my_decimal
|
||||
{
|
||||
Decimal_from_str(const char *str, size_t strlen): my_decimal()
|
||||
{
|
||||
const char *end= &(str[strlen]);
|
||||
[[maybe_unused]] int unexpected_error= str2my_decimal(
|
||||
E_DEC_ERROR, str, this, const_cast<char **>(&end));
|
||||
DBUG_ASSERT(!unexpected_error && !*end);
|
||||
}
|
||||
};
|
||||
/*
|
||||
The ideal use would work with `double`s, including the `*1000` step,
|
||||
but disappointingly, the double interfaces of @ref decimal_t are
|
||||
implemented by printing into a string and parsing that char array.
|
||||
*/
|
||||
static const auto MAX_PERIOD= Decimal_from_str(STRING_WITH_LEN(MAX)),
|
||||
THOUSAND = Decimal_from_str(STRING_WITH_LEN("1000"));
|
||||
ulonglong decimal_out;
|
||||
if (decimal.sign || decimal_cmp(&MAX_PERIOD, &decimal) < 0)
|
||||
return true; // ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE
|
||||
overprecise= decimal.frac > 3;
|
||||
// decomposed from my_decimal2int() to reduce a bit of computations
|
||||
auto rounded= my_decimal(), product= my_decimal();
|
||||
int unexpected_error=
|
||||
decimal_round(&decimal, &rounded, 3, HALF_UP) |
|
||||
decimal_mul(&rounded, &THOUSAND, &product) |
|
||||
decimal2ulonglong(&product, &decimal_out);
|
||||
DBUG_ASSERT(!unexpected_error);
|
||||
result= static_cast<uint32_t>(decimal_out);
|
||||
return unexpected_error;
|
||||
}
|
||||
/** Load from a '\0'-terminated string
|
||||
@param expected_end This function also checks that the exclusive end
|
||||
of the decimal *(which may be `str_end` itself)* is this delimiter.
|
||||
@return from_decimal(), or `true` on unexpected contents
|
||||
@post Output arguments are not changed on error.
|
||||
*/
|
||||
static uint from_chars(
|
||||
std::optional<uint32_t> &self, const char *str,
|
||||
const char *str_end, bool &overprecise, char expected_end= '\n'
|
||||
)
|
||||
{
|
||||
uint32_t result;
|
||||
auto decimal= my_decimal();
|
||||
if (str2my_decimal(
|
||||
E_DEC_ERROR, str, &decimal, const_cast<char **>(&str_end)
|
||||
) || *str_end != expected_end ||
|
||||
from_decimal(result, decimal, overprecise))
|
||||
return true;
|
||||
self.emplace(result);
|
||||
return false;
|
||||
}
|
||||
bool load_from(IO_CACHE *file) override
|
||||
{
|
||||
/**
|
||||
Number of chars Optional_int_value::load_from() uses plus
|
||||
1 for the decimal point; truncate the excess precision,
|
||||
which there should not be unless the file is edited externally.
|
||||
*/
|
||||
char buf[Int_IO_CACHE::BUF_SIZE<uint32_t> + 3];
|
||||
bool overprecise;
|
||||
size_t length= my_b_gets(file, buf, sizeof(buf));
|
||||
return !length ||
|
||||
from_chars(optional, buf, &(buf[length]), overprecise) || overprecise;
|
||||
}
|
||||
/**
|
||||
This method is engineered (that is, hard-coded) to take
|
||||
full advantage of the non-negative `DECIMAL(10,3)` format.
|
||||
*/
|
||||
void save_to(IO_CACHE *file) override {
|
||||
char buf[Int_IO_CACHE::BUF_SIZE<uint32_t> - /* decimal part */ 3];
|
||||
auto[integer_part, decimal_part]= div(operator uint32_t(), 1000);
|
||||
std::to_chars_result result=
|
||||
std::to_chars(buf, &buf[sizeof(buf)], integer_part);
|
||||
DBUG_ASSERT(result.ec == Int_IO_CACHE::ERRC_OK);
|
||||
my_b_write(file, reinterpret_cast<const uchar *>(buf), result.ptr - buf);
|
||||
my_b_write_byte(file, '.');
|
||||
result= std::to_chars(buf, &buf[sizeof(buf)], decimal_part);
|
||||
DBUG_ASSERT(result.ec == Int_IO_CACHE::ERRC_OK);
|
||||
for (ptrdiff_t digits= result.ptr - buf; digits < 3; ++digits)
|
||||
my_b_write_byte(file, '0');
|
||||
my_b_write(file, reinterpret_cast<const uchar *>(buf), result.ptr - buf);
|
||||
}
|
||||
}
|
||||
/// `Slave_heartbeat_period` of SHOW ALL SLAVES STATUS
|
||||
master_heartbeat_period;
|
||||
|
||||
/// }@
|
||||
|
||||
|
||||
inline static Mem_fn::List VALUE_LIST= {
|
||||
&Master_info_file::master_log_file,
|
||||
&Master_info_file::master_log_pos,
|
||||
&Master_info_file::master_host,
|
||||
&Master_info_file::master_user,
|
||||
&Master_info_file::master_password,
|
||||
&Master_info_file::master_port,
|
||||
&Master_info_file::master_connect_retry,
|
||||
&Master_info_file::master_ssl,
|
||||
&Master_info_file::master_ssl_ca,
|
||||
&Master_info_file::master_ssl_capath,
|
||||
&Master_info_file::master_ssl_cert,
|
||||
&Master_info_file::master_ssl_cipher,
|
||||
&Master_info_file::master_ssl_key,
|
||||
&Master_info_file::master_ssl_verify_server_cert,
|
||||
&Master_info_file::master_heartbeat_period,
|
||||
nullptr, // &Master_info_file::master_bind, // MDEV-19248
|
||||
&Master_info_file::ignore_server_ids,
|
||||
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
|
||||
};
|
||||
|
||||
/**
|
||||
Guard agaist extra left-overs at the end of file in case a later update
|
||||
causes the effective content to shrink compared to earlier contents
|
||||
*/
|
||||
static constexpr const char END_MARKER[]= "END_MARKER";
|
||||
/** A keyed iterable for the `key=value` section of `@@master_info_file`.
|
||||
For bidirectional compatibility with MySQL
|
||||
(codenames only at this writing) and earlier versions of MariaDB,
|
||||
keys should match the corresponding old property name in @ref Master_info.
|
||||
*/
|
||||
// C++ default allocator to match that `mysql_execute_command()` uses `new`
|
||||
inline static const std::unordered_map<std::string_view, Mem_fn> VALUE_MAP= {
|
||||
/*
|
||||
These are here to annotate whether they are `DEFAULT`.
|
||||
They are repeated from @ref VALUE_LIST to enable bidirectional
|
||||
compatibility with MySQL and earlier versions of MariaDB
|
||||
(where unrecognized keys, such as those from the future, are ignored).
|
||||
*/
|
||||
{"connect_retry" , &Master_info_file::master_connect_retry },
|
||||
{"ssl" , &Master_info_file::master_ssl },
|
||||
{"ssl_ca" , &Master_info_file::master_ssl_ca },
|
||||
{"ssl_capath" , &Master_info_file::master_ssl_capath },
|
||||
{"ssl_cert" , &Master_info_file::master_ssl_cert },
|
||||
{"ssl_cipher" , &Master_info_file::master_ssl_cipher },
|
||||
{"ssl_key" , &Master_info_file::master_ssl_key },
|
||||
{"ssl_crl" , &Master_info_file::master_ssl_crl },
|
||||
{"ssl_crlpath" , &Master_info_file::master_ssl_crlpath },
|
||||
{"ssl_verify_server_cert",
|
||||
&Master_info_file::master_ssl_verify_server_cert},
|
||||
{"heartbeat_period" , &Master_info_file::master_heartbeat_period },
|
||||
{"retry_count" , &Master_info_file::master_retry_count },
|
||||
// These are the ones new in MariaDB.
|
||||
{"using_gtid", &Master_info_file::master_use_gtid },
|
||||
{"do_domain_ids", &Master_info_file::do_domain_ids },
|
||||
{"ignore_domain_ids", &Master_info_file::ignore_domain_ids},
|
||||
{END_MARKER, nullptr}
|
||||
};
|
||||
|
||||
|
||||
Master_info_file(
|
||||
DYNAMIC_ARRAY &ignore_server_ids,
|
||||
DYNAMIC_ARRAY &do_domain_ids, DYNAMIC_ARRAY &ignore_domain_ids
|
||||
):
|
||||
ignore_server_ids(ignore_server_ids),
|
||||
do_domain_ids(do_domain_ids), ignore_domain_ids(ignore_domain_ids)
|
||||
{
|
||||
for(auto &[_, mem_fn]: VALUE_MAP)
|
||||
if (mem_fn)
|
||||
mem_fn(this).set_default();
|
||||
}
|
||||
|
||||
bool load_from_file() override
|
||||
{
|
||||
/// Repurpose the trailing `\0` spot to prepare for the `=` or `\n`
|
||||
static constexpr size_t LONGEST_KEY_SIZE= sizeof("ssl_verify_server_cert");
|
||||
if (Info_file::load_from_file(VALUE_LIST, /* MASTER_CONNECT_RETRY */ 7))
|
||||
return true;
|
||||
/*
|
||||
Info_file::load_from_file() is only for fixed-position entries.
|
||||
Proceed with `key=value` lines for MariaDB 10.0 and above:
|
||||
The "value" can then be read individually after consuming the`key=`.
|
||||
*/
|
||||
/**
|
||||
MariaDB 10.0 does not have the `END_MARKER` before any left-overs at
|
||||
the end of the file, so ignore any non-first occurrences of a key.
|
||||
@note
|
||||
This set only "contains" the static strings of @ref VALUE_MAP's keys,
|
||||
which means it can simply compare pointers by face values rather than
|
||||
their pointed content, in contrast with how `HASH` of `include/hash.h`
|
||||
is designed for string contents in a specified charset.
|
||||
*/
|
||||
auto seen= std::unordered_set<const char *>();
|
||||
while (true)
|
||||
{
|
||||
/**
|
||||
A `key=value` line might not actually have the `=value` part;
|
||||
in this case, it means this value was set_default().
|
||||
*/
|
||||
bool found_equal= false;
|
||||
char key[LONGEST_KEY_SIZE];
|
||||
for (size_t i= 0; i < LONGEST_KEY_SIZE; ++i)
|
||||
{
|
||||
switch (int c= my_b_get(&file)) {
|
||||
case my_b_EOF:
|
||||
return i; // OK if no chars were read, or error if the line hits EOF.
|
||||
case '=':
|
||||
found_equal= true;
|
||||
[[fallthrough]];
|
||||
case '\n':
|
||||
{
|
||||
decltype(VALUE_MAP)::const_iterator kv=
|
||||
VALUE_MAP.find(std::string_view(
|
||||
key,
|
||||
i // size = exclusive end index of the string
|
||||
));
|
||||
// The "unknown" lines would be ignored to facilitate downgrades.
|
||||
if (kv != VALUE_MAP.cend()) // found
|
||||
{
|
||||
const char *key= kv->first.data();
|
||||
if (key == END_MARKER)
|
||||
return false;
|
||||
/**
|
||||
The `second` member of std::unordered_set::insert()'s return
|
||||
is `true` for a new insertion or `false` for a duplicate.
|
||||
*/
|
||||
else if (seen.insert(key).second)
|
||||
{
|
||||
Persistent &value= kv->second(this);
|
||||
if (found_equal ? value.load_from(&file) : value.set_default())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
goto break_for;
|
||||
}
|
||||
default:
|
||||
key[i]= static_cast<char>(c);
|
||||
}
|
||||
}
|
||||
break_for:;
|
||||
}
|
||||
}
|
||||
|
||||
void save_to_file() override
|
||||
{
|
||||
// Write the line-based section with some reservations for MySQL additions
|
||||
Info_file::save_to_file(VALUE_LIST, 33);
|
||||
/* Write MariaDB `key=value` lines:
|
||||
The "value" can then be written individually after generating the`key=`.
|
||||
*/
|
||||
for (auto &[key, pm]: VALUE_MAP)
|
||||
if (pm)
|
||||
{
|
||||
Persistent &value= pm(this);
|
||||
my_b_write(&file,
|
||||
reinterpret_cast<const uchar *>(key.data()), key.size());
|
||||
if (!value.is_default())
|
||||
{
|
||||
my_b_write_byte(&file, '=');
|
||||
value.save_to(&file);
|
||||
}
|
||||
my_b_write_byte(&file, '\n');
|
||||
}
|
||||
my_b_write(&file, reinterpret_cast<const uchar *>(END_MARKER),
|
||||
sizeof(END_MARKER) - /* the '\0' */ 1);
|
||||
my_b_write_byte(&file, '\n');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
563
sql/rpl_mi.cc
563
sql/rpl_mi.cc
@@ -26,23 +26,20 @@
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
|
||||
#define DEFAULT_CONNECT_RETRY 60
|
||||
|
||||
static void init_master_log_pos(Master_info* mi);
|
||||
|
||||
Master_info::Master_info(LEX_CSTRING *connection_name_arg,
|
||||
bool is_slave_recovery)
|
||||
:Slave_reporting_capability("I/O"),
|
||||
ssl(1), ssl_verify_server_cert(1), fd(-1), io_thd(0),
|
||||
rli(is_slave_recovery), port(MYSQL_PORT),
|
||||
bool is_slave_recovery):
|
||||
Master_info_file(ignore_server_ids, domain_id_filter.m_domain_ids[0],
|
||||
domain_id_filter.m_domain_ids[1]),
|
||||
Slave_reporting_capability("I/O"), fd(-1), io_thd(0), rli(is_slave_recovery),
|
||||
checksum_alg_before_fd(BINLOG_CHECKSUM_ALG_UNDEF),
|
||||
connect_retry(DEFAULT_CONNECT_RETRY), retry_count(master_retry_count),
|
||||
connects_tried(0), binlog_storage_engine(0), inited(0), abort_slave(0),
|
||||
slave_running(MYSQL_SLAVE_NOT_RUN), slave_run_id(0),
|
||||
clock_diff_with_master(0),
|
||||
sync_counter(0), heartbeat_period(0), received_heartbeats(0),
|
||||
sync_counter(0), received_heartbeats(0),
|
||||
master_id(0), prev_master_id(0),
|
||||
using_gtid(USE_GTID_SLAVE_POS), events_queued_since_last_gtid(0),
|
||||
events_queued_since_last_gtid(0),
|
||||
gtid_reconnect_event_skip_count(0), gtid_event_seen(false),
|
||||
in_start_all_slaves(0), in_stop_all_slaves(0), in_flush_all_relay_logs(0),
|
||||
users(0), killed(0),
|
||||
@@ -50,10 +47,8 @@ Master_info::Master_info(LEX_CSTRING *connection_name_arg,
|
||||
semi_sync_reply_enabled(0)
|
||||
{
|
||||
char *tmp;
|
||||
port= MYSQL_PORT;
|
||||
host[0] = 0; user[0] = 0; password[0] = 0;
|
||||
ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
|
||||
ssl_cipher[0]= 0; ssl_key[0]= 0;
|
||||
ssl_crl[0]= 0; ssl_crlpath[0]= 0;
|
||||
|
||||
/*
|
||||
Store connection name and lower case connection name
|
||||
@@ -149,18 +144,6 @@ Master_info::~Master_info()
|
||||
free_root(&mem_root, MYF(0));
|
||||
}
|
||||
|
||||
/**
|
||||
A comparison function to be supplied as argument to @c sort_dynamic()
|
||||
and @c bsearch()
|
||||
|
||||
@return -1 if first argument is less, 0 if it equal to, 1 if it is greater
|
||||
than the second
|
||||
*/
|
||||
static int change_master_id_cmp(const void *id1, const void *id2)
|
||||
{
|
||||
return (*(ulong *) id1 - *(ulong *) id2);
|
||||
}
|
||||
|
||||
/**
|
||||
Reports if the s_id server has been configured to ignore events
|
||||
it generates with
|
||||
@@ -197,142 +180,20 @@ void Master_info::clear_in_memory_info(bool all)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
Master_info::using_gtid_astext(enum enum_using_gtid arg)
|
||||
{
|
||||
switch (arg)
|
||||
{
|
||||
case USE_GTID_NO:
|
||||
return "No";
|
||||
case USE_GTID_SLAVE_POS:
|
||||
return "Slave_Pos";
|
||||
default:
|
||||
DBUG_ASSERT(arg == USE_GTID_CURRENT_POS);
|
||||
return "Current_Pos";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void init_master_log_pos(Master_info* mi)
|
||||
{
|
||||
DBUG_ENTER("init_master_log_pos");
|
||||
|
||||
mi->master_log_name[0] = 0;
|
||||
mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number
|
||||
if (mi->master_supports_gtid)
|
||||
{
|
||||
mi->using_gtid= Master_info::USE_GTID_SLAVE_POS;
|
||||
}
|
||||
mi->master_use_gtid.set_default();
|
||||
mi->master_heartbeat_period.set_default();
|
||||
mi->gtid_current_pos.reset();
|
||||
mi->events_queued_since_last_gtid= 0;
|
||||
mi->gtid_reconnect_event_skip_count= 0;
|
||||
mi->gtid_event_seen= false;
|
||||
|
||||
/*
|
||||
always request heartbeat unless master_heartbeat_period is set
|
||||
explicitly zero. Here is the default value for heartbeat period
|
||||
if CHANGE MASTER did not specify it. (no data loss in conversion
|
||||
as hb period has a max)
|
||||
*/
|
||||
mi->heartbeat_period= (float) MY_MIN(SLAVE_MAX_HEARTBEAT_PERIOD,
|
||||
(slave_net_timeout/2.0));
|
||||
DBUG_ASSERT(mi->heartbeat_period > (float) 0.001
|
||||
|| mi->heartbeat_period == 0);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/**
|
||||
Parses the IO_CACHE for "key=" and returns the "key".
|
||||
If no '=' found, returns the whole line (for END_MARKER).
|
||||
|
||||
@param key [OUT] Key buffer
|
||||
@param max_size [IN] Maximum buffer size
|
||||
@param f [IN] IO_CACHE file
|
||||
@param found_equal [OUT] Set true if a '=' was found.
|
||||
|
||||
@retval 0 Either "key=" or '\n' found
|
||||
@retval 1 EOF
|
||||
*/
|
||||
static int
|
||||
read_mi_key_from_file(char *key, int max_size, IO_CACHE *f, bool *found_equal)
|
||||
{
|
||||
int i= 0, c;
|
||||
|
||||
DBUG_ENTER("read_key_from_file");
|
||||
|
||||
*found_equal= false;
|
||||
if (max_size <= 0)
|
||||
DBUG_RETURN(1);
|
||||
for (;;)
|
||||
{
|
||||
if (i >= max_size-1)
|
||||
{
|
||||
key[i] = '\0';
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
c= my_b_get(f);
|
||||
if (c == my_b_EOF)
|
||||
{
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
else if (c == '\n')
|
||||
{
|
||||
key[i]= '\0';
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (c == '=')
|
||||
{
|
||||
key[i]= '\0';
|
||||
*found_equal= true;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
key[i]= c;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
/* NotReached */
|
||||
}
|
||||
|
||||
enum {
|
||||
LINES_IN_MASTER_INFO_WITH_SSL= 14,
|
||||
|
||||
/* 5.1.16 added value of master_ssl_verify_server_cert */
|
||||
LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT= 15,
|
||||
|
||||
/* 5.5 added value of master_heartbeat_period */
|
||||
LINE_FOR_MASTER_HEARTBEAT_PERIOD= 16,
|
||||
|
||||
/* MySQL Cluster 6.3 added master_bind */
|
||||
LINE_FOR_MASTER_BIND = 17,
|
||||
|
||||
/* 6.0 added value of master_ignore_server_id */
|
||||
LINE_FOR_REPLICATE_IGNORE_SERVER_IDS= 18,
|
||||
|
||||
/* 6.0 added value of master_uuid */
|
||||
LINE_FOR_MASTER_UUID= 19,
|
||||
|
||||
/* line for master_retry_count */
|
||||
LINE_FOR_MASTER_RETRY_COUNT= 20,
|
||||
|
||||
/* line for ssl_crl */
|
||||
LINE_FOR_SSL_CRL= 21,
|
||||
|
||||
/* line for ssl_crl */
|
||||
LINE_FOR_SSL_CRLPATH= 22,
|
||||
|
||||
/* MySQL 5.6 fixed-position lines. */
|
||||
LINE_FOR_FIRST_MYSQL_5_6=23,
|
||||
LINE_FOR_LAST_MYSQL_5_6=23,
|
||||
/* Reserved lines for MySQL future versions. */
|
||||
LINE_FOR_LAST_MYSQL_FUTURE=33,
|
||||
/* Number of (fixed-position) lines used when saving master info file */
|
||||
LINES_IN_MASTER_INFO= LINE_FOR_LAST_MYSQL_FUTURE
|
||||
};
|
||||
|
||||
int init_master_info(Master_info* mi, const char* master_info_fname,
|
||||
const char* slave_info_fname,
|
||||
bool abort_if_no_master_info_file,
|
||||
@@ -454,236 +315,15 @@ file '%s')", fname);
|
||||
}
|
||||
|
||||
mi->fd = fd;
|
||||
int port, connect_retry, master_log_pos, lines;
|
||||
int ssl= 0, ssl_verify_server_cert= 0;
|
||||
float master_heartbeat_period= 0.0;
|
||||
char *first_non_digit;
|
||||
char buf[HOSTNAME_LENGTH+1];
|
||||
|
||||
/*
|
||||
Starting from 4.1.x master.info has new format. Now its
|
||||
first line contains number of lines in file. By reading this
|
||||
number we will be always distinguish to which version our
|
||||
master.info corresponds to. We can't simply count lines in
|
||||
file since versions before 4.1.x could generate files with more
|
||||
lines than needed.
|
||||
If first line doesn't contain a number or contain number less than
|
||||
LINES_IN_MASTER_INFO_WITH_SSL then such file is treated like file
|
||||
from pre 4.1.1 version.
|
||||
There is no ambiguity when reading an old master.info, as before
|
||||
4.1.1, the first line contained the binlog's name, which is either
|
||||
empty or has an extension (contains a '.'), so can't be confused
|
||||
with an integer.
|
||||
|
||||
So we're just reading first line and trying to figure which version
|
||||
is this.
|
||||
*/
|
||||
|
||||
/*
|
||||
The first row is temporarily stored in mi->master_log_name,
|
||||
if it is line count and not binlog name (new format) it will be
|
||||
overwritten by the second row later.
|
||||
*/
|
||||
if (init_strvar_from_file(mi->master_log_name,
|
||||
sizeof(mi->master_log_name), &mi->file,
|
||||
""))
|
||||
if (mi->load_from_file())
|
||||
goto errwithmsg;
|
||||
|
||||
lines= strtoul(mi->master_log_name, &first_non_digit, 10);
|
||||
|
||||
if (mi->master_log_name[0]!='\0' &&
|
||||
*first_non_digit=='\0' && lines >= LINES_IN_MASTER_INFO_WITH_SSL)
|
||||
{
|
||||
/* Seems to be new format => read master log name from next line */
|
||||
if (init_strvar_from_file(mi->master_log_name,
|
||||
sizeof(mi->master_log_name), &mi->file, ""))
|
||||
goto errwithmsg;
|
||||
}
|
||||
else
|
||||
lines= 7;
|
||||
|
||||
if (init_intvar_from_file(&master_log_pos, &mi->file, 4) ||
|
||||
init_strvar_from_file(mi->host, sizeof(mi->host), &mi->file, 0) ||
|
||||
init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file, "test") ||
|
||||
init_strvar_from_file(mi->password, sizeof(mi->password),
|
||||
&mi->file, 0) ||
|
||||
init_intvar_from_file(&port, &mi->file, MYSQL_PORT) ||
|
||||
init_intvar_from_file(&connect_retry, &mi->file,
|
||||
DEFAULT_CONNECT_RETRY))
|
||||
goto errwithmsg;
|
||||
|
||||
/*
|
||||
If file has ssl part use it even if we have server without
|
||||
SSL support. But these options will be ignored later when
|
||||
slave will try connect to master, so in this case warning
|
||||
is printed.
|
||||
*/
|
||||
if (lines >= LINES_IN_MASTER_INFO_WITH_SSL)
|
||||
{
|
||||
if (init_intvar_from_file(&ssl, &mi->file, 0) ||
|
||||
init_strvar_from_file(mi->ssl_ca, sizeof(mi->ssl_ca),
|
||||
&mi->file, 0) ||
|
||||
init_strvar_from_file(mi->ssl_capath, sizeof(mi->ssl_capath),
|
||||
&mi->file, 0) ||
|
||||
init_strvar_from_file(mi->ssl_cert, sizeof(mi->ssl_cert),
|
||||
&mi->file, 0) ||
|
||||
init_strvar_from_file(mi->ssl_cipher, sizeof(mi->ssl_cipher),
|
||||
&mi->file, 0) ||
|
||||
init_strvar_from_file(mi->ssl_key, sizeof(mi->ssl_key),
|
||||
&mi->file, 0))
|
||||
goto errwithmsg;
|
||||
|
||||
/*
|
||||
Starting from 5.1.16 ssl_verify_server_cert might be
|
||||
in the file
|
||||
*/
|
||||
if (lines >= LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT &&
|
||||
init_intvar_from_file(&ssl_verify_server_cert, &mi->file, 0))
|
||||
goto errwithmsg;
|
||||
/*
|
||||
Starting from 6.0 master_heartbeat_period might be
|
||||
in the file
|
||||
*/
|
||||
if (lines >= LINE_FOR_MASTER_HEARTBEAT_PERIOD &&
|
||||
init_floatvar_from_file(&master_heartbeat_period, &mi->file, 0.0))
|
||||
goto errwithmsg;
|
||||
/*
|
||||
Starting from MySQL Cluster 6.3 master_bind might be in the file
|
||||
(this is just a reservation to avoid future upgrade problems)
|
||||
*/
|
||||
if (lines >= LINE_FOR_MASTER_BIND &&
|
||||
init_strvar_from_file(buf, sizeof(buf), &mi->file, ""))
|
||||
goto errwithmsg;
|
||||
/*
|
||||
Starting from 6.0 list of server_id of ignorable servers might be
|
||||
in the file
|
||||
*/
|
||||
if (lines >= LINE_FOR_REPLICATE_IGNORE_SERVER_IDS &&
|
||||
init_dynarray_intvar_from_file(&mi->ignore_server_ids, &mi->file))
|
||||
{
|
||||
sql_print_error("Failed to initialize master info ignore_server_ids");
|
||||
goto errwithmsg;
|
||||
}
|
||||
|
||||
/* reserved */
|
||||
if (lines >= LINE_FOR_MASTER_UUID &&
|
||||
init_strvar_from_file(buf, sizeof(buf), &mi->file, ""))
|
||||
goto errwithmsg;
|
||||
|
||||
/* Starting from 5.5 the master_retry_count may be in the repository. */
|
||||
if (lines >= LINE_FOR_MASTER_RETRY_COUNT)
|
||||
{
|
||||
if (init_strvar_from_file(buf, sizeof(buf), &mi->file, ""))
|
||||
goto errwithmsg;
|
||||
mi->retry_count = atol(buf);
|
||||
}
|
||||
|
||||
if (lines >= LINE_FOR_SSL_CRLPATH &&
|
||||
(init_strvar_from_file(mi->ssl_crl, sizeof(mi->ssl_crl),
|
||||
&mi->file, "") ||
|
||||
init_strvar_from_file(mi->ssl_crlpath, sizeof(mi->ssl_crlpath),
|
||||
&mi->file, "")))
|
||||
goto errwithmsg;
|
||||
|
||||
/*
|
||||
Starting with MariaDB 10.0, we use a key=value syntax, which is nicer
|
||||
in several ways. But we leave a bunch of empty lines to accomodate
|
||||
any future old-style additions in MySQL (this will make it easier for
|
||||
users moving from MariaDB to MySQL, to not have MySQL try to
|
||||
interpret a MariaDB key=value line.)
|
||||
*/
|
||||
if (lines >= LINE_FOR_LAST_MYSQL_FUTURE)
|
||||
{
|
||||
uint i;
|
||||
bool got_eq;
|
||||
bool seen_using_gtid= false;
|
||||
bool seen_do_domain_ids=false, seen_ignore_domain_ids=false;
|
||||
|
||||
/* Skip lines used by / reserved for MySQL >= 5.6. */
|
||||
for (i= LINE_FOR_FIRST_MYSQL_5_6; i <= LINE_FOR_LAST_MYSQL_FUTURE; ++i)
|
||||
{
|
||||
if (init_strvar_from_file(buf, sizeof(buf), &mi->file, ""))
|
||||
goto errwithmsg;
|
||||
}
|
||||
|
||||
/*
|
||||
Parse any extra key=value lines. read_key_from_file() parses the file
|
||||
for "key=" and returns the "key" if found. The "value" can then the
|
||||
parsed on case by case basis. The "unknown" lines would be ignored to
|
||||
facilitate downgrades.
|
||||
10.0 does not have the END_MARKER before any left-overs at the end
|
||||
of the file. So ignore any but the first occurrence of a key.
|
||||
*/
|
||||
while (!read_mi_key_from_file(buf, sizeof(buf), &mi->file, &got_eq))
|
||||
{
|
||||
if (got_eq && !seen_using_gtid && !strcmp(buf, "using_gtid"))
|
||||
{
|
||||
int val;
|
||||
if (!init_intvar_from_file(&val, &mi->file, 0))
|
||||
{
|
||||
if (val == Master_info::USE_GTID_CURRENT_POS)
|
||||
mi->using_gtid= Master_info::USE_GTID_CURRENT_POS;
|
||||
else if (val == Master_info::USE_GTID_SLAVE_POS)
|
||||
mi->using_gtid= Master_info::USE_GTID_SLAVE_POS;
|
||||
else
|
||||
mi->using_gtid= Master_info::USE_GTID_NO;
|
||||
seen_using_gtid= true;
|
||||
} else {
|
||||
sql_print_error("Failed to initialize master info using_gtid");
|
||||
goto errwithmsg;
|
||||
}
|
||||
}
|
||||
else if (got_eq && !seen_do_domain_ids && !strcmp(buf, "do_domain_ids"))
|
||||
{
|
||||
if (mi->domain_id_filter.init_ids(&mi->file,
|
||||
Domain_id_filter::DO_DOMAIN_IDS))
|
||||
{
|
||||
sql_print_error("Failed to initialize master info do_domain_ids");
|
||||
goto errwithmsg;
|
||||
}
|
||||
seen_do_domain_ids= true;
|
||||
}
|
||||
else if (got_eq && !seen_ignore_domain_ids &&
|
||||
!strcmp(buf, "ignore_domain_ids"))
|
||||
{
|
||||
if (mi->domain_id_filter.init_ids(&mi->file,
|
||||
Domain_id_filter::IGNORE_DOMAIN_IDS))
|
||||
{
|
||||
sql_print_error("Failed to initialize master info "
|
||||
"ignore_domain_ids");
|
||||
goto errwithmsg;
|
||||
}
|
||||
seen_ignore_domain_ids= true;
|
||||
}
|
||||
else if (!got_eq && !strcmp(buf, "END_MARKER"))
|
||||
{
|
||||
/*
|
||||
Guard agaist extra left-overs at the end of file, in case a later
|
||||
update causes the file to shrink compared to earlier contents.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_OPENSSL
|
||||
if (ssl)
|
||||
if (mi->master_ssl)
|
||||
sql_print_warning("SSL information in the master info file "
|
||||
"('%s') are ignored because this MySQL slave was "
|
||||
"compiled without SSL support.", fname);
|
||||
#endif /* HAVE_OPENSSL */
|
||||
|
||||
/*
|
||||
This has to be handled here as init_intvar_from_file can't handle
|
||||
my_off_t types
|
||||
*/
|
||||
mi->master_log_pos= (my_off_t) master_log_pos;
|
||||
mi->port= (uint) port;
|
||||
mi->connect_retry= (uint) connect_retry;
|
||||
mi->ssl= (my_bool) ssl;
|
||||
mi->ssl_verify_server_cert= ssl_verify_server_cert;
|
||||
mi->heartbeat_period= MY_MIN(SLAVE_MAX_HEARTBEAT_PERIOD, master_heartbeat_period);
|
||||
}
|
||||
DBUG_PRINT("master_info",("log_file_name: %s position: %ld",
|
||||
mi->master_log_name,
|
||||
@@ -728,7 +368,6 @@ int flush_master_info(Master_info* mi,
|
||||
bool need_lock_relay_log)
|
||||
{
|
||||
IO_CACHE* file = &mi->file;
|
||||
char lbuf[22];
|
||||
int err= 0;
|
||||
|
||||
DBUG_ENTER("flush_master_info");
|
||||
@@ -764,45 +403,6 @@ int flush_master_info(Master_info* mi,
|
||||
DBUG_RETURN(2);
|
||||
}
|
||||
|
||||
/*
|
||||
produce a line listing the total number and all the ignored server_id:s
|
||||
*/
|
||||
char* ignore_server_ids_buf;
|
||||
{
|
||||
ignore_server_ids_buf=
|
||||
(char *) my_malloc(PSI_INSTRUMENT_ME,
|
||||
(sizeof(global_system_variables.server_id) * 3 + 1) *
|
||||
(1 + mi->ignore_server_ids.elements), MYF(MY_WME));
|
||||
if (!ignore_server_ids_buf)
|
||||
DBUG_RETURN(1); /* error */
|
||||
ulong cur_len= sprintf(ignore_server_ids_buf, "%zu",
|
||||
mi->ignore_server_ids.elements);
|
||||
for (ulong i= 0; i < mi->ignore_server_ids.elements; i++)
|
||||
{
|
||||
ulong s_id;
|
||||
get_dynamic(&mi->ignore_server_ids, (uchar*) &s_id, i);
|
||||
cur_len+= sprintf(ignore_server_ids_buf + cur_len, " %lu", s_id);
|
||||
}
|
||||
}
|
||||
|
||||
char *do_domain_ids_buf= 0, *ignore_domain_ids_buf= 0;
|
||||
|
||||
do_domain_ids_buf=
|
||||
mi->domain_id_filter.as_string(Domain_id_filter::DO_DOMAIN_IDS);
|
||||
if (do_domain_ids_buf == NULL)
|
||||
{
|
||||
err= 1; /* error */
|
||||
goto done;
|
||||
}
|
||||
|
||||
ignore_domain_ids_buf=
|
||||
mi->domain_id_filter.as_string(Domain_id_filter::IGNORE_DOMAIN_IDS);
|
||||
if (ignore_domain_ids_buf == NULL)
|
||||
{
|
||||
err= 1; /* error */
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
We flushed the relay log BEFORE the master.info file, because if we crash
|
||||
now, we will get a duplicate event in the relay log at restart. If we
|
||||
@@ -811,34 +411,7 @@ int flush_master_info(Master_info* mi,
|
||||
can add detection and scrap one event; with a hole there's nothing we can
|
||||
do).
|
||||
*/
|
||||
|
||||
/*
|
||||
In certain cases this code may create master.info files that seems
|
||||
corrupted, because of extra lines filled with garbage in the end
|
||||
file (this happens if new contents take less space than previous
|
||||
contents of file). But because of number of lines in the first line
|
||||
of file we don't care about this garbage.
|
||||
*/
|
||||
char heartbeat_buf[FLOATING_POINT_BUFFER];
|
||||
my_fcvt(mi->heartbeat_period, 3, heartbeat_buf, NULL);
|
||||
my_b_seek(file, 0L);
|
||||
my_b_printf(file,
|
||||
"%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n"
|
||||
"\n\n\n\n\n\n\n\n\n\n\n"
|
||||
"using_gtid=%d\n"
|
||||
"do_domain_ids=%s\n"
|
||||
"ignore_domain_ids=%s\n"
|
||||
"END_MARKER\n",
|
||||
LINES_IN_MASTER_INFO,
|
||||
mi->master_log_name, llstr(mi->master_log_pos, lbuf),
|
||||
mi->host, mi->user,
|
||||
mi->password, mi->port, mi->connect_retry,
|
||||
(int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert,
|
||||
mi->ssl_cipher, mi->ssl_key, mi->ssl_verify_server_cert,
|
||||
heartbeat_buf, "", ignore_server_ids_buf,
|
||||
"", mi->retry_count,
|
||||
mi->ssl_crl, mi->ssl_crlpath, mi->using_gtid,
|
||||
do_domain_ids_buf, ignore_domain_ids_buf);
|
||||
mi->save_to_file();
|
||||
err= flush_io_cache(file);
|
||||
if (sync_masterinfo_period && !err &&
|
||||
++(mi->sync_counter) >= sync_masterinfo_period)
|
||||
@@ -849,11 +422,6 @@ int flush_master_info(Master_info* mi,
|
||||
|
||||
/* Fix err; flush_io_cache()/my_sync() may return -1 */
|
||||
err= (err != 0) ? 1 : 0;
|
||||
|
||||
done:
|
||||
my_free(ignore_server_ids_buf);
|
||||
my_free(do_domain_ids_buf);
|
||||
my_free(ignore_domain_ids_buf);
|
||||
DBUG_RETURN(err);
|
||||
}
|
||||
|
||||
@@ -1105,7 +673,7 @@ bool Master_info_index::init_all_master_info()
|
||||
{
|
||||
int thread_mask;
|
||||
int err_num= 0, succ_num= 0; // The number of success read Master_info
|
||||
char sign[MAX_CONNECTION_NAME+1];
|
||||
Info_file::String_value<MAX_CONNECTION_NAME+1> sign;
|
||||
File index_file_nr;
|
||||
THD *thd;
|
||||
DBUG_ENTER("init_all_master_info");
|
||||
@@ -1143,8 +711,7 @@ bool Master_info_index::init_all_master_info()
|
||||
thd->store_globals();
|
||||
|
||||
reinit_io_cache(&index_file, READ_CACHE, 0L,0,0);
|
||||
while (!init_strvar_from_file(sign, sizeof(sign),
|
||||
&index_file, NULL))
|
||||
while (!sign.load_from(&index_file))
|
||||
{
|
||||
LEX_CSTRING connection_name;
|
||||
Master_info *mi;
|
||||
@@ -1888,7 +1455,7 @@ bool Domain_id_filter::update_ids(DYNAMIC_ARRAY *do_ids,
|
||||
return true;
|
||||
}
|
||||
|
||||
if (using_gtid == Master_info::USE_GTID_NO &&
|
||||
if (!using_gtid &&
|
||||
(!do_list_empty || !ignore_list_empty))
|
||||
{
|
||||
sql_print_error("DO_DOMAIN_IDS or IGNORE_DOMAIN_IDS lists can't be "
|
||||
@@ -1907,22 +1474,6 @@ bool Domain_id_filter::update_ids(DYNAMIC_ARRAY *do_ids,
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
Serialize and store the ids from domain id lists into the thd's protocol
|
||||
buffer.
|
||||
|
||||
@param thd [IN] thread handler
|
||||
|
||||
@retval void
|
||||
*/
|
||||
void Domain_id_filter::store_ids(THD *thd)
|
||||
{
|
||||
for (int i= DO_DOMAIN_IDS; i <= IGNORE_DOMAIN_IDS; i ++)
|
||||
{
|
||||
prot_store_ids(thd, &m_domain_ids[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Domain_id_filter::store_ids(Field ***field)
|
||||
{
|
||||
for (int i= DO_DOMAIN_IDS; i <= IGNORE_DOMAIN_IDS; i ++)
|
||||
@@ -1931,59 +1482,6 @@ void Domain_id_filter::store_ids(Field ***field)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize the given domain_id list (DYNAMIC_ARRAY) with the
|
||||
space-separated list of numbers from the specified IO_CACHE where
|
||||
the first number represents the total number of entries to follows.
|
||||
|
||||
@param f [IN] IO_CACHE file
|
||||
@param type [IN] domain id list type
|
||||
|
||||
@retval false Success
|
||||
true Error
|
||||
*/
|
||||
bool Domain_id_filter::init_ids(IO_CACHE *f, enum_list_type type)
|
||||
{
|
||||
return init_dynarray_intvar_from_file(&m_domain_ids[type], f);
|
||||
}
|
||||
|
||||
/**
|
||||
Return the elements of the give domain id list type as string.
|
||||
|
||||
@param type [IN] domain id list type
|
||||
|
||||
@retval a string buffer storing the total number
|
||||
of elements followed by the individual
|
||||
elements (space-separated) in the
|
||||
specified list.
|
||||
|
||||
Note: Its caller's responsibility to free the returned string buffer.
|
||||
*/
|
||||
char *Domain_id_filter::as_string(enum_list_type type)
|
||||
{
|
||||
char *buf;
|
||||
size_t sz;
|
||||
DYNAMIC_ARRAY *ids= &m_domain_ids[type];
|
||||
|
||||
sz= (sizeof(ulong) * 3 + 1) * (1 + ids->elements);
|
||||
|
||||
if (!(buf= (char *) my_malloc(PSI_INSTRUMENT_ME, sz, MYF(MY_WME))))
|
||||
return NULL;
|
||||
|
||||
// Store the total number of elements followed by the individual elements.
|
||||
size_t cur_len= sprintf(buf, "%zu", ids->elements);
|
||||
sz-= cur_len;
|
||||
|
||||
for (uint i= 0; i < ids->elements; i++)
|
||||
{
|
||||
ulong domain_id;
|
||||
get_dynamic(ids, (void *) &domain_id, i);
|
||||
cur_len+= my_snprintf(buf + cur_len, sz, " %lu", domain_id);
|
||||
sz-= cur_len;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void update_change_master_ids(DYNAMIC_ARRAY *new_ids, DYNAMIC_ARRAY *old_ids)
|
||||
{
|
||||
reset_dynamic(old_ids);
|
||||
@@ -2031,24 +1529,6 @@ static size_t store_ids(DYNAMIC_ARRAY *ids, char *buff, size_t buff_len)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Serialize and store the ids from the given ids DYNAMIC_ARRAY into the thd's
|
||||
protocol buffer.
|
||||
|
||||
@param thd [IN] thread handler
|
||||
@param ids [IN] ids list
|
||||
|
||||
@retval void
|
||||
*/
|
||||
|
||||
void prot_store_ids(THD *thd, DYNAMIC_ARRAY *ids)
|
||||
{
|
||||
char buff[FN_REFLEN];
|
||||
size_t cur_len= store_ids(ids, buff, sizeof(buff));
|
||||
thd->protocol->store(buff, cur_len, &my_charset_bin);
|
||||
}
|
||||
|
||||
|
||||
void field_store_ids(Field *field, DYNAMIC_ARRAY *ids)
|
||||
{
|
||||
char buff[FN_REFLEN];
|
||||
@@ -2115,14 +1595,15 @@ void setup_mysql_connection_for_master(MYSQL *mysql, Master_info *mi,
|
||||
mysql_options(mysql, MYSQL_OPT_READ_TIMEOUT, (char *) &timeout);
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
if (mi->ssl)
|
||||
if (mi->master_ssl)
|
||||
{
|
||||
mysql_ssl_set(mysql, mi->ssl_key, mi->ssl_cert, mi->ssl_ca, mi->ssl_capath,
|
||||
mi->ssl_cipher);
|
||||
mysql_options(mysql, MYSQL_OPT_SSL_CRL, mi->ssl_crl);
|
||||
mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, mi->ssl_crlpath);
|
||||
mysql_ssl_set(mysql,
|
||||
mi->master_ssl_key, mi->master_ssl_cert, mi->master_ssl_ca,
|
||||
mi->master_ssl_capath, mi->master_ssl_cipher);
|
||||
mysql_options(mysql, MYSQL_OPT_SSL_CRL, mi->master_ssl_crl);
|
||||
mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, mi->master_ssl_crlpath);
|
||||
mysql_options(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
|
||||
&mi->ssl_verify_server_cert);
|
||||
&mi->master_ssl_verify_server_cert);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
84
sql/rpl_mi.h
84
sql/rpl_mi.h
@@ -18,6 +18,7 @@
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
|
||||
#include "rpl_master_info_file.h"
|
||||
#include "rpl_rli.h"
|
||||
#include "rpl_reporting.h"
|
||||
#include <my_sys.h>
|
||||
@@ -96,44 +97,8 @@ public:
|
||||
bool update_ids(DYNAMIC_ARRAY *do_ids, DYNAMIC_ARRAY *ignore_ids,
|
||||
bool using_gtid);
|
||||
|
||||
/*
|
||||
Serialize and store the ids from domain id lists into the thd's protocol
|
||||
buffer.
|
||||
|
||||
@param thd [IN] thread handler
|
||||
|
||||
@retval void
|
||||
*/
|
||||
void store_ids(THD *thd);
|
||||
/* Same as above, but store the id's into a group of fields */
|
||||
/// Serialize and store the ids from domain id lists into a group of fields.
|
||||
void store_ids(Field ***field);
|
||||
/*
|
||||
Initialize the given domain id list (DYNAMIC_ARRAY) with the
|
||||
space-separated list of numbers from the specified IO_CACHE where
|
||||
the first number is the total number of entries to follows.
|
||||
|
||||
@param f [IN] IO_CACHE file
|
||||
@param type [IN] domain id list type
|
||||
|
||||
@retval false Success
|
||||
true Error
|
||||
*/
|
||||
bool init_ids(IO_CACHE *f, enum_list_type type);
|
||||
|
||||
/*
|
||||
Return the elements of the give domain id list type as string.
|
||||
|
||||
@param type [IN] domain id list type
|
||||
|
||||
@retval a string buffer storing the total number
|
||||
of elements followed by the individual
|
||||
elements (space-separated) in the
|
||||
specified list.
|
||||
|
||||
Note: Its caller's responsibility to free the returned string buffer.
|
||||
*/
|
||||
char *as_string(enum_list_type type);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -184,12 +149,14 @@ typedef struct st_rows_event_tracker
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
class Master_info : public Slave_reporting_capability
|
||||
class Master_info: public Master_info_file, public Slave_reporting_capability
|
||||
{
|
||||
public:
|
||||
enum enum_using_gtid {
|
||||
USE_GTID_NO= 0, USE_GTID_CURRENT_POS= 1, USE_GTID_SLAVE_POS= 2
|
||||
};
|
||||
/// @deprecated use the new namespace instead
|
||||
inline static constexpr enum_master_use_gtid
|
||||
USE_GTID_NO = enum_master_use_gtid::NO,
|
||||
USE_GTID_CURRENT_POS= enum_master_use_gtid::CURRENT_POS,
|
||||
USE_GTID_SLAVE_POS = enum_master_use_gtid::SLAVE_POS;
|
||||
|
||||
Master_info(LEX_CSTRING *connection_name, bool is_slave_recovery);
|
||||
~Master_info();
|
||||
@@ -200,7 +167,11 @@ class Master_info : public Slave_reporting_capability
|
||||
/* If malloc() in initialization failed */
|
||||
return connection_name.str == 0;
|
||||
}
|
||||
static const char *using_gtid_astext(enum enum_using_gtid arg);
|
||||
inline const char *using_gtid_astext(enum_master_use_gtid arg)
|
||||
{
|
||||
DBUG_ASSERT(arg <= enum_master_use_gtid::DEFAULT);
|
||||
return master_use_gtid_names[static_cast<size_t>(arg)];
|
||||
}
|
||||
bool using_parallel()
|
||||
{
|
||||
return opt_slave_parallel_threads > 0 &&
|
||||
@@ -222,21 +193,16 @@ class Master_info : public Slave_reporting_capability
|
||||
}
|
||||
|
||||
/* the variables below are needed because we can change masters on the fly */
|
||||
char master_log_name[FN_REFLEN+6]; /* Room for multi-*/
|
||||
char host[HOSTNAME_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1];
|
||||
char user[USERNAME_LENGTH+1];
|
||||
char password[MAX_PASSWORD_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1];
|
||||
char (&master_log_name)[FN_REFLEN]= master_log_file.buf;
|
||||
char (&host)[HOSTNAME_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1]= master_host.buf;
|
||||
char (&user)[USERNAME_LENGTH+1]= master_user.buf;
|
||||
char (&password)[MAX_PASSWORD_LENGTH*SYSTEM_CHARSET_MBMAXLEN+1]=
|
||||
master_password.buf;
|
||||
LEX_CSTRING connection_name; /* User supplied connection name */
|
||||
LEX_CSTRING cmp_connection_name; /* Connection name in lower case */
|
||||
bool ssl; // enables use of SSL connection if true
|
||||
char ssl_ca[FN_REFLEN], ssl_capath[FN_REFLEN], ssl_cert[FN_REFLEN];
|
||||
char ssl_cipher[FN_REFLEN], ssl_key[FN_REFLEN];
|
||||
char ssl_crl[FN_REFLEN], ssl_crlpath[FN_REFLEN];
|
||||
my_bool ssl_verify_server_cert; /* MUST be my_bool, see mysql_option() */
|
||||
|
||||
my_off_t master_log_pos;
|
||||
my_off_t &master_log_pos= Master_info_file::master_log_pos.value;
|
||||
File fd; // we keep the file open, so we need to remember the file pointer
|
||||
IO_CACHE file;
|
||||
|
||||
mysql_mutex_t data_lock, run_lock, sleep_lock, start_stop_lock, start_alter_lock, start_alter_list_lock;
|
||||
mysql_cond_t data_cond, start_cond, stop_cond, sleep_cond;
|
||||
@@ -245,7 +211,7 @@ class Master_info : public Slave_reporting_capability
|
||||
uint32 file_id; /* for 3.23 load data infile */
|
||||
uint mysql_version;
|
||||
Relay_log_info rli;
|
||||
uint port;
|
||||
uint32_t &port= master_port.value;
|
||||
Rpl_filter* rpl_filter; /* Each replication can set its filter rule*/
|
||||
/*
|
||||
to hold checksum alg in use until IO thread has received FD.
|
||||
@@ -254,9 +220,9 @@ class Master_info : public Slave_reporting_capability
|
||||
*/
|
||||
enum_binlog_checksum_alg checksum_alg_before_fd;
|
||||
/** pause duration between each connection retry */
|
||||
uint connect_retry;
|
||||
decltype(master_connect_retry) &connect_retry= master_connect_retry;
|
||||
/** per-slave @ref master_retry_count */
|
||||
ulong retry_count;
|
||||
decltype(master_retry_count) &retry_count= master_retry_count;
|
||||
/** count of connects the most-recent (or the current) connection has tried */
|
||||
ulong connects_tried;
|
||||
#ifndef DBUG_OFF
|
||||
@@ -291,7 +257,6 @@ class Master_info : public Slave_reporting_capability
|
||||
events should happen before fsyncing.
|
||||
*/
|
||||
uint sync_counter;
|
||||
float heartbeat_period; // interface with CHANGE MASTER or master.info
|
||||
ulonglong received_heartbeats; // counter of received heartbeat events
|
||||
DYNAMIC_ARRAY ignore_server_ids;
|
||||
ulong master_id;
|
||||
@@ -307,7 +272,7 @@ class Master_info : public Slave_reporting_capability
|
||||
Note that you can not change the numeric values of these, they are used
|
||||
in master.info.
|
||||
*/
|
||||
enum enum_using_gtid using_gtid;
|
||||
decltype(master_use_gtid) &using_gtid= master_use_gtid;
|
||||
|
||||
/*
|
||||
This GTID position records how far we have fetched into the relay logs.
|
||||
@@ -406,7 +371,7 @@ class Master_info : public Slave_reporting_capability
|
||||
first need to test if the master supports GTIDs. If not, fall back to 'No'.
|
||||
Cache the value so future RESET SLAVE commands don't revert to Slave_Pos.
|
||||
*/
|
||||
bool master_supports_gtid= true;
|
||||
bool &master_supports_gtid= master_use_gtid.gtid_supported;
|
||||
|
||||
/*
|
||||
When TRUE, transition this server from being an active master to a slave.
|
||||
@@ -437,7 +402,6 @@ int flush_master_info(Master_info* mi,
|
||||
bool need_lock_relay_log);
|
||||
void copy_filter_setting(Rpl_filter* dst_filter, Rpl_filter* src_filter);
|
||||
void update_change_master_ids(DYNAMIC_ARRAY *new_ids, DYNAMIC_ARRAY *old_ids);
|
||||
void prot_store_ids(THD *thd, DYNAMIC_ARRAY *ids);
|
||||
void field_store_ids(Field *field, DYNAMIC_ARRAY *ids);
|
||||
/*
|
||||
Multi master are handled trough this struct.
|
||||
|
||||
58
sql/rpl_relay_log_info_file.h
Normal file
58
sql/rpl_relay_log_info_file.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
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_RELAY_LOG_INFO_FILE_H
|
||||
#define RPL_RELAY_LOG_INFO_FILE_H
|
||||
|
||||
#include "rpl_info_file.h"
|
||||
|
||||
struct Relay_log_info_file: Info_file
|
||||
{
|
||||
/**
|
||||
`@@relay_log_info_file` values in SHOW SLAVE STATUS order
|
||||
@{
|
||||
*/
|
||||
String_value<> relay_log_file;
|
||||
Int_value<my_off_t> relay_log_pos;
|
||||
/// Relay_Master_Log_File (of the event *group*)
|
||||
String_value<> read_master_log_file;
|
||||
/// Exec_Master_Log_Pos (of the event *group*)
|
||||
Int_value<my_off_t> read_master_log_pos;
|
||||
/// SQL_Delay
|
||||
Int_value<uint32_t> sql_delay;
|
||||
/// }@
|
||||
|
||||
inline static const Mem_fn::List VALUE_LIST= {
|
||||
&Relay_log_info_file::relay_log_file,
|
||||
&Relay_log_info_file::relay_log_pos,
|
||||
&Relay_log_info_file::read_master_log_file,
|
||||
&Relay_log_info_file::read_master_log_pos,
|
||||
&Relay_log_info_file::sql_delay
|
||||
};
|
||||
|
||||
bool load_from_file() override
|
||||
{
|
||||
return Info_file::load_from_file(VALUE_LIST, /* Exec_Master_Log_Pos */ 4);
|
||||
}
|
||||
void save_to_file() override
|
||||
{
|
||||
return Info_file::save_to_file(VALUE_LIST,
|
||||
VALUE_LIST.size() + /* line count line */ 1);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
101
sql/rpl_rli.cc
101
sql/rpl_rli.cc
@@ -45,15 +45,14 @@ rpl_slave_state *rpl_global_gtid_slave_state;
|
||||
gtid_waiting rpl_global_gtid_waiting;
|
||||
|
||||
Relay_log_info::Relay_log_info(bool is_slave_recovery, const char* thread_name)
|
||||
:Slave_reporting_capability(thread_name),
|
||||
:Relay_log_info_file(), Slave_reporting_capability(thread_name),
|
||||
replicate_same_server_id(::replicate_same_server_id),
|
||||
info_fd(-1), cur_log_fd(-1), relay_log(&sync_relaylog_period),
|
||||
sync_counter(0), is_relay_log_recovery(is_slave_recovery),
|
||||
save_temporary_tables(0),
|
||||
mi(0), inuse_relaylog_list(0), last_inuse_relaylog(0),
|
||||
cur_log_old_open_count(0), error_on_rli_init_info(false),
|
||||
group_relay_log_pos(0), event_relay_log_pos(0),
|
||||
group_master_log_pos(0), log_space_total(0), ignore_log_space_limit(0),
|
||||
event_relay_log_pos(0), log_space_total(0), ignore_log_space_limit(0),
|
||||
sql_thread_caught_up(true),
|
||||
last_master_timestamp(0), newest_master_timestamp(0), slave_timestamp(0),
|
||||
slave_skip_counter(0),
|
||||
@@ -62,12 +61,12 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery, const char* thread_name)
|
||||
slave_running(MYSQL_SLAVE_NOT_RUN), until_condition(UNTIL_NONE),
|
||||
until_log_pos(0), is_until_before_gtids(false),
|
||||
retried_trans(0), executed_entries(0),
|
||||
last_trans_retry_count(0), sql_delay(0), sql_delay_end(0),
|
||||
last_trans_retry_count(0), sql_delay_end(0),
|
||||
until_relay_log_names_defer(false),
|
||||
m_flags(0)
|
||||
{
|
||||
DBUG_ENTER("Relay_log_info::Relay_log_info");
|
||||
|
||||
group_relay_log_pos= group_master_log_pos= sql_delay= 0;
|
||||
relay_log.is_relay_log= TRUE;
|
||||
relay_log_state.init();
|
||||
#ifdef HAVE_PSI_INTERFACE
|
||||
@@ -324,75 +323,10 @@ Failed to open the existing relay log info file '%s' (errno %d)",
|
||||
}
|
||||
}
|
||||
|
||||
int relay_log_pos, master_log_pos, lines;
|
||||
char *first_non_digit;
|
||||
|
||||
/*
|
||||
Starting from MySQL 5.6.x, relay-log.info has a new format.
|
||||
Now, its first line contains the number of lines in the file.
|
||||
By reading this number we can determine which version our master.info
|
||||
comes from. We can't simply count the lines in the file, since
|
||||
versions before 5.6.x could generate files with more lines than
|
||||
needed. If first line doesn't contain a number, or if it
|
||||
contains a number less than LINES_IN_RELAY_LOG_INFO_WITH_DELAY,
|
||||
then the file is treated like a file from pre-5.6.x version.
|
||||
There is no ambiguity when reading an old master.info: before
|
||||
5.6.x, the first line contained the binlog's name, which is
|
||||
either empty or has an extension (contains a '.'), so can't be
|
||||
confused with an integer.
|
||||
|
||||
So we're just reading first line and trying to figure which
|
||||
version is this.
|
||||
*/
|
||||
|
||||
/*
|
||||
The first row is temporarily stored in mi->master_log_name, if
|
||||
it is line count and not binlog name (new format) it will be
|
||||
overwritten by the second row later.
|
||||
*/
|
||||
if (init_strvar_from_file(group_relay_log_name,
|
||||
sizeof(group_relay_log_name),
|
||||
&info_file, ""))
|
||||
{
|
||||
msg="Error reading slave log configuration";
|
||||
if (load_from_file())
|
||||
goto err;
|
||||
}
|
||||
|
||||
lines= strtoul(group_relay_log_name, &first_non_digit, 10);
|
||||
|
||||
if (group_relay_log_name[0] != '\0' &&
|
||||
*first_non_digit == '\0' &&
|
||||
lines >= LINES_IN_RELAY_LOG_INFO_WITH_DELAY)
|
||||
{
|
||||
DBUG_PRINT("info", ("relay_log_info file is in new format."));
|
||||
/* Seems to be new format => read relay log name from next line */
|
||||
if (init_strvar_from_file(group_relay_log_name,
|
||||
sizeof(group_relay_log_name),
|
||||
&info_file, ""))
|
||||
{
|
||||
msg="Error reading slave log configuration";
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
else
|
||||
DBUG_PRINT("info", ("relay_log_info file is in old format."));
|
||||
|
||||
if (init_intvar_from_file(&relay_log_pos,
|
||||
&info_file, BIN_LOG_HEADER_SIZE) ||
|
||||
init_strvar_from_file(group_master_log_name,
|
||||
sizeof(group_master_log_name),
|
||||
&info_file, "") ||
|
||||
init_intvar_from_file(&master_log_pos, &info_file, 0) ||
|
||||
(lines >= LINES_IN_RELAY_LOG_INFO_WITH_DELAY &&
|
||||
init_intvar_from_file(&sql_delay, &info_file, 0)))
|
||||
{
|
||||
msg="Error reading slave log configuration";
|
||||
goto err;
|
||||
}
|
||||
|
||||
strmake_buf(event_relay_log_name,group_relay_log_name);
|
||||
group_relay_log_pos= event_relay_log_pos= relay_log_pos;
|
||||
group_master_log_pos= master_log_pos;
|
||||
event_relay_log_pos= group_relay_log_pos;
|
||||
|
||||
if (is_relay_log_recovery && init_recovery(mi, &msg))
|
||||
goto err;
|
||||
@@ -2621,11 +2555,6 @@ bool rpl_sql_thread_info::cached_charset_compare(char *charset) const
|
||||
- Error can happen if writing to file fails or if flushing the file
|
||||
fails.
|
||||
|
||||
@param rli The object representing the Relay_log_info.
|
||||
|
||||
@todo Change the log file information to a binary format to avoid
|
||||
calling longlong2str.
|
||||
|
||||
@return 0 on success, 1 on error.
|
||||
*/
|
||||
bool Relay_log_info::flush()
|
||||
@@ -2635,23 +2564,7 @@ bool Relay_log_info::flush()
|
||||
DBUG_ENTER("Relay_log_info::flush()");
|
||||
|
||||
IO_CACHE *file = &info_file;
|
||||
// 2*file name, 2*long long, 2*unsigned long, 6*'\n'
|
||||
char buff[FN_REFLEN * 2 + 22 * 2 + 10 * 2 + 6], *pos;
|
||||
my_b_seek(file, 0L);
|
||||
pos= longlong10_to_str(LINES_IN_RELAY_LOG_INFO_WITH_DELAY, buff, 10);
|
||||
*pos++='\n';
|
||||
pos=strmov(pos, group_relay_log_name);
|
||||
*pos++='\n';
|
||||
pos=longlong10_to_str(group_relay_log_pos, pos, 10);
|
||||
*pos++='\n';
|
||||
pos=strmov(pos, group_master_log_name);
|
||||
*pos++='\n';
|
||||
pos=longlong10_to_str(group_master_log_pos, pos, 10);
|
||||
*pos++='\n';
|
||||
pos= longlong10_to_str(sql_delay, pos, 10);
|
||||
*pos++= '\n';
|
||||
if (my_b_write(file, (uchar*) buff, (size_t) (pos-buff)))
|
||||
error=1;
|
||||
save_to_file();
|
||||
if (flush_io_cache(file))
|
||||
error=1;
|
||||
if (sync_relayloginfo_period &&
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#ifndef RPL_RLI_H
|
||||
#define RPL_RLI_H
|
||||
|
||||
#include "rpl_relay_log_info_file.h"
|
||||
#include "rpl_tblmap.h"
|
||||
#include "rpl_reporting.h"
|
||||
#include "rpl_utility.h"
|
||||
@@ -59,7 +60,8 @@ class Rpl_filter;
|
||||
struct rpl_group_info;
|
||||
struct inuse_relaylog;
|
||||
|
||||
class Relay_log_info : public Slave_reporting_capability
|
||||
class Relay_log_info:
|
||||
public Relay_log_info_file, public Slave_reporting_capability
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -138,7 +140,7 @@ public:
|
||||
/* The following variables are safe to read any time */
|
||||
|
||||
/* IO_CACHE of the info file - set only during init or end */
|
||||
IO_CACHE info_file;
|
||||
IO_CACHE &info_file= Info_file::file;
|
||||
|
||||
/*
|
||||
List of temporary tables used by this connection.
|
||||
@@ -209,8 +211,8 @@ public:
|
||||
!belongs_to_client(); client thread executing BINLOG statement if
|
||||
belongs_to_client()).
|
||||
*/
|
||||
char group_relay_log_name[FN_REFLEN];
|
||||
ulonglong group_relay_log_pos;
|
||||
char (&group_relay_log_name)[FN_REFLEN]= relay_log_file.buf;
|
||||
my_off_t &group_relay_log_pos= relay_log_pos.value;
|
||||
char event_relay_log_name[FN_REFLEN];
|
||||
ulonglong event_relay_log_pos;
|
||||
ulonglong future_event_relay_log_pos;
|
||||
@@ -231,8 +233,8 @@ public:
|
||||
!belongs_to_client(); client thread executing BINLOG statement if
|
||||
belongs_to_client()).
|
||||
*/
|
||||
char group_master_log_name[FN_REFLEN];
|
||||
volatile my_off_t group_master_log_pos;
|
||||
char (&group_master_log_name)[FN_REFLEN]= read_master_log_file.buf;
|
||||
my_off_t &group_master_log_pos= read_master_log_pos.value;
|
||||
|
||||
/*
|
||||
Handling of the relay_log_space_limit optional constraint.
|
||||
@@ -587,7 +589,7 @@ private:
|
||||
slave SQL thread is running, since the SQL thread reads it without
|
||||
a lock when executing Relay_log_info::flush().
|
||||
*/
|
||||
int sql_delay;
|
||||
uint32_t &sql_delay= Relay_log_info_file::sql_delay.value;
|
||||
|
||||
/**
|
||||
During a delay, specifies the point in time when the delay ends.
|
||||
|
||||
@@ -8482,11 +8482,11 @@ ER_SLAVE_HEARTBEAT_FAILURE
|
||||
spa "Datos inesperados de latido (heartbeat) de maestro (master): %s"
|
||||
sw "Data isiyotarajiwa ya mapigo ya moyo ya bwana: %s"
|
||||
ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE
|
||||
chi "心跳周期的请求值是负的或超过允许的最大值(%u秒)"
|
||||
eng "The requested value for the heartbeat period is either negative or exceeds the maximum allowed (%u seconds)"
|
||||
geo "გულისცემის პერიოდის მოთოხვნილი მნიშვნელობა ან უარყოფითა, ან მაქსიმალურ დაშვებულ მნიშვნელობას (%u წამი) აჭარბებს"
|
||||
spa "El valor requerido para el período de latido o es negativo o excede al máximo permitido (%u segundos)"
|
||||
sw "Thamani iliyoombwa kwa kipindi cha mpigo wa moyo ni hasi au inazidi kiwango cha juu kinachoruhusiwa (sekunde %u)"
|
||||
chi "心跳周期的请求值是负的或超过允许的最大值(%s秒)"
|
||||
eng "The requested value for the heartbeat period is either negative or exceeds the maximum allowed (%s seconds)"
|
||||
geo "გულისცემის პერიოდის მოთოხვნილი მნიშვნელობა ან უარყოფითა, ან მაქსიმალურ დაშვებულ მნიშვნელობას (%s წამი) აჭარბებს"
|
||||
spa "El valor requerido para el período de latido o es negativo o excede al máximo permitido (%s segundos)"
|
||||
sw "Thamani iliyoombwa kwa kipindi cha mpigo wa moyo ni hasi au inazidi kiwango cha juu kinachoruhusiwa (sekunde %s)"
|
||||
ER_UNUSED_14
|
||||
eng "You should never see it"
|
||||
geo "ამას ვერ უნდა ხედავდეთ"
|
||||
|
||||
213
sql/slave.cc
213
sql/slave.cc
@@ -1466,173 +1466,6 @@ bool net_request_file(NET* net, const char* fname)
|
||||
(uchar*) "", 0));
|
||||
}
|
||||
|
||||
#endif /* HAVE_REPLICATION */
|
||||
|
||||
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
|
||||
const char *default_val)
|
||||
{
|
||||
size_t length;
|
||||
DBUG_ENTER("init_strvar_from_file");
|
||||
|
||||
if ((length=my_b_gets(f,var, max_size)))
|
||||
{
|
||||
char* last_p = var + length -1;
|
||||
if (*last_p == '\n')
|
||||
*last_p = 0; // if we stopped on newline, kill it
|
||||
else
|
||||
{
|
||||
/*
|
||||
If we truncated a line or stopped on last char, remove all chars
|
||||
up to and including newline.
|
||||
*/
|
||||
int c;
|
||||
while (((c=my_b_get(f)) != '\n' && c != my_b_EOF)) ;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (default_val)
|
||||
{
|
||||
strmake(var, default_val, max_size-1);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/*
|
||||
when moving these functions to mysys, don't forget to
|
||||
remove slave.cc from libmysqld/CMakeLists.txt
|
||||
*/
|
||||
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
|
||||
{
|
||||
char buf[32];
|
||||
DBUG_ENTER("init_intvar_from_file");
|
||||
|
||||
|
||||
if (my_b_gets(f, buf, sizeof(buf)))
|
||||
{
|
||||
*var = atoi(buf);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (default_val)
|
||||
{
|
||||
*var = default_val;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val)
|
||||
{
|
||||
char buf[16];
|
||||
DBUG_ENTER("init_floatvar_from_file");
|
||||
|
||||
|
||||
if (my_b_gets(f, buf, sizeof(buf)))
|
||||
{
|
||||
if (sscanf(buf, "%f", var) != 1)
|
||||
DBUG_RETURN(1);
|
||||
else
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (default_val != 0.0)
|
||||
{
|
||||
*var = default_val;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
A master info read method
|
||||
|
||||
This function is called from @c init_master_info() along with
|
||||
relatives to restore some of @c active_mi members.
|
||||
Particularly, this function is responsible for restoring
|
||||
IGNORE_SERVER_IDS list of servers whose events the slave is
|
||||
going to ignore (to not log them in the relay log).
|
||||
Items being read are supposed to be decimal output of values of a
|
||||
type shorter or equal of @c long and separated by the single space.
|
||||
It also used to restore DO_DOMAIN_IDS & IGNORE_DOMAIN_IDS lists.
|
||||
|
||||
@param arr @c DYNAMIC_ARRAY pointer to storage for servers id
|
||||
@param f @c IO_CACHE pointer to the source file
|
||||
|
||||
@retval 0 All OK
|
||||
@retval non-zero An error
|
||||
*/
|
||||
|
||||
int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f)
|
||||
{
|
||||
int ret= 0;
|
||||
char buf[16 * (sizeof(long)*4 + 1)]; // static buffer to use most of times
|
||||
char *buf_act= buf; // actual buffer can be dynamic if static is short
|
||||
char *token, *last;
|
||||
uint num_items; // number of items of `arr'
|
||||
size_t read_size;
|
||||
DBUG_ENTER("init_dynarray_intvar_from_file");
|
||||
|
||||
if ((read_size= my_b_gets(f, buf_act, sizeof(buf))) == 0)
|
||||
{
|
||||
DBUG_RETURN(0); // no line in master.info
|
||||
}
|
||||
if (read_size + 1 == sizeof(buf) && buf[sizeof(buf) - 2] != '\n')
|
||||
{
|
||||
/*
|
||||
short read happend; allocate sufficient memory and make the 2nd read
|
||||
*/
|
||||
char buf_work[(sizeof(long)*3 + 1)*16];
|
||||
memcpy(buf_work, buf, sizeof(buf_work));
|
||||
num_items= atoi(strtok_r(buf_work, " ", &last));
|
||||
size_t snd_size;
|
||||
/*
|
||||
max size lower bound approximate estimation bases on the formula:
|
||||
(the items number + items themselves) *
|
||||
(decimal size + space) - 1 + `\n' + '\0'
|
||||
*/
|
||||
size_t max_size= (1 + num_items) * (sizeof(long)*3 + 1) + 1;
|
||||
buf_act= (char*) my_malloc(key_memory_Rpl_info_file_buffer, max_size,
|
||||
MYF(MY_WME));
|
||||
memcpy(buf_act, buf, read_size);
|
||||
snd_size= my_b_gets(f, buf_act + read_size, max_size - read_size);
|
||||
if (snd_size == 0 ||
|
||||
((snd_size + 1 == max_size - read_size) && buf_act[max_size - 2] != '\n'))
|
||||
{
|
||||
/*
|
||||
failure to make the 2nd read or short read again
|
||||
*/
|
||||
ret= 1;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
token= strtok_r(buf_act, " ", &last);
|
||||
if (token == NULL)
|
||||
{
|
||||
ret= 1;
|
||||
goto err;
|
||||
}
|
||||
num_items= atoi(token);
|
||||
for (uint i=0; i < num_items; i++)
|
||||
{
|
||||
token= strtok_r(NULL, " ", &last);
|
||||
if (token == NULL)
|
||||
{
|
||||
ret= 1;
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulong val= atol(token);
|
||||
insert_dynamic(arr, (uchar *) &val);
|
||||
}
|
||||
}
|
||||
err:
|
||||
if (buf_act != buf)
|
||||
my_free(buf_act);
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
|
||||
/*
|
||||
Check if the error is caused by network.
|
||||
@@ -1687,6 +1520,7 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
|
||||
MYSQL_ROW master_row;
|
||||
uint full_version= mysql_get_server_version(mysql);
|
||||
uint version= full_version/ 10000;
|
||||
uint32_t heartbeat_period= mi->master_heartbeat_period;
|
||||
DBUG_ENTER("get_master_version_and_clock");
|
||||
|
||||
/*
|
||||
@@ -2069,15 +1903,13 @@ when it try to get the value of TIME_ZONE global variable from master.";
|
||||
}
|
||||
}
|
||||
|
||||
if (mi->heartbeat_period != 0.0)
|
||||
if (heartbeat_period)
|
||||
{
|
||||
const char query_format[]= "SET @master_heartbeat_period= %llu";
|
||||
char query[sizeof(query_format) + 32];
|
||||
/*
|
||||
the period is an ulonglong of nano-secs.
|
||||
*/
|
||||
my_snprintf(query, sizeof(query), query_format,
|
||||
(ulonglong) (mi->heartbeat_period*1000000000UL));
|
||||
// The user variable is in nanoseconds
|
||||
static const char query_format[]=
|
||||
"SET @master_heartbeat_period= %" PRIu32 "000""000";
|
||||
char query[sizeof(query_format) + Int_IO_CACHE::BUF_SIZE<uint32_t>];
|
||||
my_snprintf(query, sizeof(query), query_format, heartbeat_period);
|
||||
|
||||
DBUG_EXECUTE_IF("simulate_slave_heartbeat_network_error",
|
||||
{ static ulong dbug_count= 0;
|
||||
@@ -3039,16 +2871,18 @@ void store_master_info(THD *thd, Master_info *mi, TABLE *table,
|
||||
store_string_or_null(field++, mi->rli.until_log_name);
|
||||
(*field++)->store((ulonglong) mi->rli.until_log_pos, true);
|
||||
|
||||
(*field++)->store(mi->master_ssl ?
|
||||
#ifdef HAVE_OPENSSL
|
||||
(*field++)->store(mi->ssl ? &msg_yes : &msg_no, &my_charset_bin);
|
||||
&msg_yes
|
||||
#else
|
||||
(*field++)->store(mi->ssl ? &msg_ignored: &msg_no, &my_charset_bin);
|
||||
&msg_ignored
|
||||
#endif
|
||||
store_string_or_null(field++, mi->ssl_ca);
|
||||
store_string_or_null(field++, mi->ssl_capath);
|
||||
store_string_or_null(field++, mi->ssl_cert);
|
||||
store_string_or_null(field++, mi->ssl_cipher);
|
||||
store_string_or_null(field++, mi->ssl_key);
|
||||
: &msg_no, &my_charset_bin);
|
||||
store_string_or_null(field++, mi->master_ssl_ca);
|
||||
store_string_or_null(field++, mi->master_ssl_capath);
|
||||
store_string_or_null(field++, mi->master_ssl_cert);
|
||||
store_string_or_null(field++, mi->master_ssl_cipher);
|
||||
store_string_or_null(field++, mi->master_ssl_key);
|
||||
|
||||
/*
|
||||
Seconds_Behind_Master: if SQL thread is running and I/O thread is
|
||||
@@ -3100,7 +2934,7 @@ void store_master_info(THD *thd, Master_info *mi, TABLE *table,
|
||||
else
|
||||
(*field++)->set_null();
|
||||
|
||||
(*field++)->store(mi->ssl_verify_server_cert? &msg_yes : &msg_no,
|
||||
(*field++)->store(mi->master_ssl_verify_server_cert? &msg_yes : &msg_no,
|
||||
&my_charset_bin);
|
||||
|
||||
// Last_IO_Errno
|
||||
@@ -3117,9 +2951,9 @@ void store_master_info(THD *thd, Master_info *mi, TABLE *table,
|
||||
(*field++)->store((uint32) mi->master_id, true);
|
||||
// SQL_Delay
|
||||
// Master_Ssl_Crl
|
||||
store_string_or_null(field++, mi->ssl_crl);
|
||||
store_string_or_null(field++, mi->master_ssl_crl);
|
||||
// Master_Ssl_Crlpath
|
||||
store_string_or_null(field++, mi->ssl_crlpath);
|
||||
store_string_or_null(field++, mi->master_ssl_crlpath);
|
||||
// Using_Gtid
|
||||
store_string_or_null(field++, mi->using_gtid_astext(mi->using_gtid));
|
||||
// Gtid_IO_Pos
|
||||
@@ -3165,7 +2999,7 @@ void store_master_info(THD *thd, Master_info *mi, TABLE *table,
|
||||
(*field++)->store((ulonglong) mi->rli.max_relay_log_size, true);
|
||||
(*field++)->store(mi->rli.executed_entries, true);
|
||||
(*field++)->store((uint) mi->received_heartbeats, true);
|
||||
(*field++)->store((double) mi->heartbeat_period);
|
||||
(*field++)->store(mi->master_heartbeat_period / 1000.0);
|
||||
(*field++)->store(gtid_pos->ptr(), gtid_pos->length(), &my_charset_bin);
|
||||
|
||||
/*
|
||||
@@ -3381,7 +3215,7 @@ static int request_dump(THD *thd, MYSQL* mysql, Master_info* mi,
|
||||
else
|
||||
sql_print_error("Error on COM_BINLOG_DUMP: %d %s, will retry in %d secs",
|
||||
mysql_errno(mysql), mysql_error(mysql),
|
||||
mi->connect_retry);
|
||||
static_cast<uint32_t>(mi->master_connect_retry));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
@@ -7062,10 +6896,11 @@ static int connect_to_master(THD* thd, MYSQL* mysql, Master_info* mi,
|
||||
suppress_warnings= 0;
|
||||
mi->report(ERROR_LEVEL, last_errno, NULL,
|
||||
"error %s to master '%s@%s:%d'"
|
||||
" - retry-time: %d maximum-retries: %lu message: %s",
|
||||
" - retry-time: %d maximum-retries: %" PRIu64 " message: %s",
|
||||
(reconnect ? "reconnecting" : "connecting"),
|
||||
mi->user, mi->host, mi->port,
|
||||
mi->connect_retry, mi->retry_count,
|
||||
static_cast<uint32_t>(mi->master_connect_retry),
|
||||
static_cast<uint64_t>(mi->master_retry_count),
|
||||
mysql_error(mysql));
|
||||
}
|
||||
if ((++(mi->connects_tried) == mi->retry_count) && mi->retry_count)
|
||||
|
||||
24
sql/slave.h
24
sql/slave.h
@@ -32,16 +32,6 @@
|
||||
@file
|
||||
*/
|
||||
|
||||
/**
|
||||
Some of defines are need in parser even though replication is not
|
||||
compiled in (embedded).
|
||||
*/
|
||||
|
||||
/**
|
||||
The maximum is defined as (ULONG_MAX/1000) with 4 bytes ulong
|
||||
*/
|
||||
#define SLAVE_MAX_HEARTBEAT_PERIOD 4294967
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
|
||||
#include "log.h"
|
||||
@@ -64,12 +54,6 @@ class Master_info_index;
|
||||
struct rpl_group_info;
|
||||
struct rpl_parallel_thread;
|
||||
|
||||
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
|
||||
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
|
||||
const char *default_val);
|
||||
int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val);
|
||||
int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f);
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
MySQL Replication
|
||||
@@ -129,7 +113,7 @@ int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f);
|
||||
(so that you have to update the .index file).
|
||||
*/
|
||||
|
||||
extern ulong master_retry_count;
|
||||
extern uint64_t master_retry_count;
|
||||
extern MY_BITMAP slave_error_mask;
|
||||
extern char slave_skip_error_names[];
|
||||
extern bool use_slave_mask;
|
||||
@@ -267,12 +251,6 @@ int apply_event_and_update_pos(Log_event* ev, THD* thd,
|
||||
int apply_event_and_update_pos_for_parallel(Log_event* ev, THD* thd,
|
||||
struct rpl_group_info *rgi);
|
||||
|
||||
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
|
||||
int init_floatvar_from_file(float* var, IO_CACHE* f, float default_val);
|
||||
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
|
||||
const char *default_val);
|
||||
int init_dynarray_intvar_from_file(DYNAMIC_ARRAY* arr, IO_CACHE* f);
|
||||
|
||||
pthread_handler_t handle_slave_io(void *arg);
|
||||
void slave_output_error_info(rpl_group_info *rgi, THD *thd);
|
||||
pthread_handler_t handle_slave_sql(void *arg);
|
||||
|
||||
@@ -369,7 +369,8 @@ struct LEX_MASTER_INFO
|
||||
ulong server_id;
|
||||
uint port, connect_retry;
|
||||
ulong retry_count;
|
||||
float heartbeat_period;
|
||||
my_decimal heartbeat_period;
|
||||
my_decimal *heartbeat_opt;
|
||||
int sql_delay;
|
||||
bool is_demotion_opt;
|
||||
bool is_until_before_gtids;
|
||||
@@ -380,7 +381,7 @@ struct LEX_MASTER_INFO
|
||||
changed variable or if it should be left at old value
|
||||
*/
|
||||
enum {LEX_MI_UNCHANGED= 0, LEX_MI_DISABLE, LEX_MI_ENABLE}
|
||||
ssl, ssl_verify_server_cert, heartbeat_opt, repl_ignore_server_ids_opt,
|
||||
ssl, ssl_verify_server_cert, repl_ignore_server_ids_opt,
|
||||
repl_do_domain_ids_opt, repl_ignore_domain_ids_opt;
|
||||
enum {
|
||||
LEX_GTID_UNCHANGED, LEX_GTID_NO, LEX_GTID_CURRENT_POS, LEX_GTID_SLAVE_POS
|
||||
@@ -388,14 +389,16 @@ struct LEX_MASTER_INFO
|
||||
|
||||
void init()
|
||||
{
|
||||
bzero(this, sizeof(*this));
|
||||
reset(false);
|
||||
connection_name= null_clex_str;
|
||||
heartbeat_period.init();
|
||||
show_all_slaves= false;
|
||||
my_init_dynamic_array(PSI_INSTRUMENT_ME, &repl_ignore_server_ids,
|
||||
sizeof(::server_id), 0, 16, MYF(0));
|
||||
my_init_dynamic_array(PSI_INSTRUMENT_ME, &repl_do_domain_ids,
|
||||
sizeof(ulong), 0, 16, MYF(0));
|
||||
my_init_dynamic_array(PSI_INSTRUMENT_ME, &repl_ignore_domain_ids,
|
||||
sizeof(ulong), 0, 16, MYF(0));
|
||||
sql_delay= -1;
|
||||
}
|
||||
void reset(bool is_change_master)
|
||||
{
|
||||
@@ -410,8 +413,8 @@ struct LEX_MASTER_INFO
|
||||
host= user= password= log_file_name= ssl_key= ssl_cert= ssl_ca=
|
||||
ssl_capath= ssl_cipher= ssl_crl= ssl_crlpath= relay_log_name= NULL;
|
||||
pos= relay_log_pos= server_id= retry_count= port= connect_retry= 0;
|
||||
heartbeat_period= 0;
|
||||
ssl= ssl_verify_server_cert= heartbeat_opt=
|
||||
heartbeat_opt= nullptr;
|
||||
ssl= ssl_verify_server_cert=
|
||||
repl_ignore_server_ids_opt= repl_do_domain_ids_opt=
|
||||
repl_ignore_domain_ids_opt= LEX_MI_UNCHANGED;
|
||||
gtid_pos_str= null_clex_str;
|
||||
|
||||
@@ -4418,7 +4418,7 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
|
||||
char saved_host[HOSTNAME_LENGTH + 1];
|
||||
uint saved_port;
|
||||
char saved_log_name[FN_REFLEN];
|
||||
Master_info::enum_using_gtid saved_using_gtid;
|
||||
enum_master_use_gtid saved_using_gtid;
|
||||
char master_info_file_tmp[FN_REFLEN];
|
||||
char relay_log_info_file_tmp[FN_REFLEN];
|
||||
my_off_t saved_log_pos;
|
||||
@@ -4565,11 +4565,28 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
|
||||
mi->retry_count= lex_mi->retry_count;
|
||||
mi->connects_tried= 0;
|
||||
}
|
||||
if (lex_mi->heartbeat_opt != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
|
||||
mi->heartbeat_period = lex_mi->heartbeat_period;
|
||||
else
|
||||
mi->heartbeat_period= (float) MY_MIN(SLAVE_MAX_HEARTBEAT_PERIOD,
|
||||
(slave_net_timeout/2.0));
|
||||
if (lex_mi->heartbeat_opt)
|
||||
{
|
||||
bool overprecise;
|
||||
ret= Master_info_file::Heartbeat_period_field::from_decimal(
|
||||
mi->master_heartbeat_period.optional, *lex_mi->heartbeat_opt, overprecise
|
||||
);
|
||||
if (ret)
|
||||
{
|
||||
my_error(ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE, MYF(0),
|
||||
Master_info_file::Heartbeat_period_field::MAX);
|
||||
goto err;
|
||||
}
|
||||
uint32_t milliseconds= *(mi->master_heartbeat_period.optional);
|
||||
if (unlikely(milliseconds > slave_net_timeout*1000ULL))
|
||||
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX,
|
||||
ER_THD(thd, ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX));
|
||||
else if (unlikely(!milliseconds && overprecise))
|
||||
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN,
|
||||
ER_THD(thd, ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN));
|
||||
}
|
||||
mi->received_heartbeats= 0; // counter lives until master is CHANGEd
|
||||
|
||||
/*
|
||||
@@ -4597,29 +4614,29 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
|
||||
}
|
||||
|
||||
if (lex_mi->ssl != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
|
||||
mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::LEX_MI_ENABLE);
|
||||
mi->master_ssl= (lex_mi->ssl == LEX_MASTER_INFO::LEX_MI_ENABLE);
|
||||
|
||||
if (lex_mi->sql_delay != -1)
|
||||
mi->rli.set_sql_delay(lex_mi->sql_delay);
|
||||
|
||||
if (lex_mi->ssl_verify_server_cert != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
|
||||
mi->ssl_verify_server_cert=
|
||||
mi->master_ssl_verify_server_cert=
|
||||
(lex_mi->ssl_verify_server_cert == LEX_MASTER_INFO::LEX_MI_ENABLE);
|
||||
|
||||
if (lex_mi->ssl_ca)
|
||||
strmake_buf(mi->ssl_ca, lex_mi->ssl_ca);
|
||||
mi->master_ssl_ca = lex_mi->ssl_ca;
|
||||
if (lex_mi->ssl_capath)
|
||||
strmake_buf(mi->ssl_capath, lex_mi->ssl_capath);
|
||||
mi->master_ssl_capath = lex_mi->ssl_capath;
|
||||
if (lex_mi->ssl_cert)
|
||||
strmake_buf(mi->ssl_cert, lex_mi->ssl_cert);
|
||||
mi->master_ssl_cert = lex_mi->ssl_cert;
|
||||
if (lex_mi->ssl_cipher)
|
||||
strmake_buf(mi->ssl_cipher, lex_mi->ssl_cipher);
|
||||
mi->master_ssl_cipher = lex_mi->ssl_cipher;
|
||||
if (lex_mi->ssl_key)
|
||||
strmake_buf(mi->ssl_key, lex_mi->ssl_key);
|
||||
mi->master_ssl_key = lex_mi->ssl_key;
|
||||
if (lex_mi->ssl_crl)
|
||||
strmake_buf(mi->ssl_crl, lex_mi->ssl_crl);
|
||||
mi->master_ssl_crl = lex_mi->ssl_crl;
|
||||
if (lex_mi->ssl_crlpath)
|
||||
strmake_buf(mi->ssl_crlpath, lex_mi->ssl_crlpath);
|
||||
mi->master_ssl_crlpath= lex_mi->ssl_crlpath;
|
||||
|
||||
#ifndef HAVE_OPENSSL
|
||||
if (lex_mi->ssl || lex_mi->ssl_ca || lex_mi->ssl_capath ||
|
||||
|
||||
@@ -2387,31 +2387,8 @@ master_def:
|
||||
|
||||
| MASTER_HEARTBEAT_PERIOD_SYM '=' NUM_literal
|
||||
{
|
||||
Lex->mi.heartbeat_period= (float) $3->val_real();
|
||||
if (unlikely(Lex->mi.heartbeat_period >
|
||||
SLAVE_MAX_HEARTBEAT_PERIOD) ||
|
||||
unlikely(Lex->mi.heartbeat_period < 0.0))
|
||||
my_yyabort_error((ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE, MYF(0),
|
||||
SLAVE_MAX_HEARTBEAT_PERIOD));
|
||||
|
||||
if (unlikely(Lex->mi.heartbeat_period > slave_net_timeout))
|
||||
{
|
||||
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX,
|
||||
ER_THD(thd, ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MAX));
|
||||
}
|
||||
if (unlikely(Lex->mi.heartbeat_period < 0.001))
|
||||
{
|
||||
if (unlikely(Lex->mi.heartbeat_period != 0.0))
|
||||
{
|
||||
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN,
|
||||
ER_THD(thd, ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE_MIN));
|
||||
Lex->mi.heartbeat_period= 0.0;
|
||||
}
|
||||
Lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_DISABLE;
|
||||
}
|
||||
Lex->mi.heartbeat_opt= LEX_MASTER_INFO::LEX_MI_ENABLE;
|
||||
Lex->mi.heartbeat_opt= $3->val_decimal(&(Lex->mi.heartbeat_period));
|
||||
DEBUG_ASSERT(Lex->mi.heartbeat_opt);
|
||||
}
|
||||
| IGNORE_SERVER_IDS_SYM '=' '(' ignore_server_id_list ')'
|
||||
{
|
||||
|
||||
@@ -184,6 +184,7 @@ void table_replication_connection_configuration::make_row(Master_info *mi)
|
||||
{
|
||||
DBUG_ENTER("table_replication_connection_configuration::make_row");
|
||||
char * temp_store;
|
||||
const char *const_temp_store;
|
||||
bool error= false;
|
||||
|
||||
m_row_exists= false;
|
||||
@@ -214,50 +215,52 @@ void table_replication_connection_configuration::make_row(Master_info *mi)
|
||||
else
|
||||
m_row.using_gtid= PS_USE_GTID_SLAVE_POS;
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
m_row.ssl_allowed= mi->ssl? PS_SSL_ALLOWED_YES:PS_SSL_ALLOWED_NO;
|
||||
#else
|
||||
m_row.ssl_allowed= mi->ssl? PS_SSL_ALLOWED_IGNORED:PS_SSL_ALLOWED_NO;
|
||||
#endif
|
||||
m_row.ssl_allowed= mi->master_ssl ?
|
||||
#ifdef HAVE_OPENSSL
|
||||
PS_SSL_ALLOWED_YES
|
||||
#else
|
||||
PS_SSL_ALLOWED_IGNORED
|
||||
#endif
|
||||
: PS_SSL_ALLOWED_NO;
|
||||
|
||||
temp_store= (char*)mi->ssl_ca;
|
||||
m_row.ssl_ca_file_length= static_cast<uint>(strlen(temp_store));
|
||||
memcpy(m_row.ssl_ca_file, temp_store, m_row.ssl_ca_file_length);
|
||||
const_temp_store= mi->master_ssl_ca;
|
||||
m_row.ssl_ca_file_length= static_cast<uint>(strlen(const_temp_store));
|
||||
memcpy(m_row.ssl_ca_file, const_temp_store, m_row.ssl_ca_file_length);
|
||||
|
||||
temp_store= (char*)mi->ssl_capath;
|
||||
m_row.ssl_ca_path_length= static_cast<uint>(strlen(temp_store));
|
||||
memcpy(m_row.ssl_ca_path, temp_store, m_row.ssl_ca_path_length);
|
||||
const_temp_store= mi->master_ssl_capath;
|
||||
m_row.ssl_ca_path_length= static_cast<uint>(strlen(const_temp_store));
|
||||
memcpy(m_row.ssl_ca_path, const_temp_store, m_row.ssl_ca_path_length);
|
||||
|
||||
temp_store= (char*)mi->ssl_cert;
|
||||
m_row.ssl_certificate_length= static_cast<uint>(strlen(temp_store));
|
||||
memcpy(m_row.ssl_certificate, temp_store, m_row.ssl_certificate_length);
|
||||
const_temp_store= mi->master_ssl_cert;
|
||||
m_row.ssl_certificate_length= static_cast<uint>(strlen(const_temp_store));
|
||||
memcpy(m_row.ssl_certificate, const_temp_store, m_row.ssl_certificate_length);
|
||||
|
||||
temp_store= (char*)mi->ssl_cipher;
|
||||
m_row.ssl_cipher_length= static_cast<uint>(strlen(temp_store));
|
||||
memcpy(m_row.ssl_cipher, temp_store, m_row.ssl_cipher_length);
|
||||
const_temp_store= mi->master_ssl_cipher;
|
||||
m_row.ssl_cipher_length= static_cast<uint>(strlen(const_temp_store));
|
||||
memcpy(m_row.ssl_cipher, const_temp_store, m_row.ssl_cipher_length);
|
||||
|
||||
temp_store= (char*)mi->ssl_key;
|
||||
m_row.ssl_key_length= static_cast<uint>(strlen(temp_store));
|
||||
memcpy(m_row.ssl_key, temp_store, m_row.ssl_key_length);
|
||||
const_temp_store= mi->master_ssl_key;
|
||||
m_row.ssl_key_length= static_cast<uint>(strlen(const_temp_store));
|
||||
memcpy(m_row.ssl_key, const_temp_store, m_row.ssl_key_length);
|
||||
|
||||
if (mi->ssl_verify_server_cert)
|
||||
if (mi->master_ssl_verify_server_cert)
|
||||
m_row.ssl_verify_server_certificate= PS_RPL_YES;
|
||||
else
|
||||
m_row.ssl_verify_server_certificate= PS_RPL_NO;
|
||||
|
||||
temp_store= (char*)mi->ssl_crl;
|
||||
m_row.ssl_crl_file_length= static_cast<uint>(strlen(temp_store));
|
||||
memcpy(m_row.ssl_crl_file, temp_store, m_row.ssl_crl_file_length);
|
||||
const_temp_store= mi->master_ssl_crl;
|
||||
m_row.ssl_crl_file_length= static_cast<uint>(strlen(const_temp_store));
|
||||
memcpy(m_row.ssl_crl_file, const_temp_store, m_row.ssl_crl_file_length);
|
||||
|
||||
temp_store= (char*)mi->ssl_crlpath;
|
||||
m_row.ssl_crl_path_length= static_cast<uint>(strlen(temp_store));
|
||||
memcpy(m_row.ssl_crl_path, temp_store, m_row.ssl_crl_path_length);
|
||||
const_temp_store= mi->master_ssl_crlpath;
|
||||
m_row.ssl_crl_path_length= static_cast<uint>(strlen(const_temp_store));
|
||||
memcpy(m_row.ssl_crl_path, const_temp_store, m_row.ssl_crl_path_length);
|
||||
|
||||
m_row.connection_retry_interval= (unsigned int) mi->connect_retry;
|
||||
|
||||
m_row.connection_retry_count= mi->retry_count;
|
||||
|
||||
m_row.heartbeat_interval= (double)mi->heartbeat_period;
|
||||
m_row.heartbeat_interval= mi->master_heartbeat_period / 1000.0;
|
||||
|
||||
m_row.ignore_server_ids= convert_array_to_str(&mi->ignore_server_ids);
|
||||
if (m_row.ignore_server_ids == NULL)
|
||||
|
||||
@@ -94,7 +94,7 @@ struct st_row_connect_config {
|
||||
char ssl_crl_path[FN_REFLEN];
|
||||
uint ssl_crl_path_length;
|
||||
uint connection_retry_interval;
|
||||
ulong connection_retry_count;
|
||||
ulonglong connection_retry_count;
|
||||
double heartbeat_interval;
|
||||
char *ignore_server_ids;
|
||||
uint ignore_server_ids_length;
|
||||
|
||||
Reference in New Issue
Block a user