2022-01-04 15:47:38 +02:00

544 lines
16 KiB
C++

/*
* Copyright (c) 2018 MariaDB Corporation Ab
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
*
* Change Date: 2026-01-04
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#pragma once
#include <maxscale/ccdefs.hh>
#include <mutex>
#include <string>
#include <unordered_map>
#include <maxbase/average.hh>
#include <maxscale/ssl.hh>
#include <maxscale/modinfo.h>
/**
* Server configuration parameters names
*/
extern const char CN_MONITORPW[];
extern const char CN_MONITORUSER[];
extern const char CN_PERSISTMAXTIME[];
extern const char CN_PERSISTPOOLMAX[];
extern const char CN_PROXY_PROTOCOL[];
extern const char CN_RANK[];
// The enum values for `rank`
extern const MXS_ENUM_VALUE rank_values[];
// Default value for `rank`
extern const char* DEFAULT_RANK;
/**
* Status bits in the SERVER->status member, which describes the general state of a server. Although the
* individual bits are independent, not all combinations make sense or are used. The bitfield is 64bits wide.
*/
// Bits used by most monitors
#define SERVER_RUNNING (1 << 0) /**<< The server is up and running */
#define SERVER_MAINT (1 << 1) /**<< Server is in maintenance mode */
#define SERVER_AUTH_ERROR (1 << 2) /**<< Authentication error from monitor */
#define SERVER_MASTER (1 << 3) /**<< The server is a master, i.e. can handle writes */
#define SERVER_SLAVE (1 << 4) /**<< The server is a slave, i.e. can handle reads */
#define SERVER_DRAINING (1 << 5) /**<< The server is being drained, i.e. no new connection
* should be created. */
#define SERVER_DISK_SPACE_EXHAUSTED (1 << 6) /**<< The disk space of the server is exhausted */
// Bits used by MariaDB Monitor (mostly)
#define SERVER_SLAVE_OF_EXT_MASTER (1 << 16) /**<< Server is slave of a non-monitored master */
#define SERVER_RELAY (1 << 17) /**<< Server is a relay */
#define SERVER_WAS_MASTER (1 << 18) /**<< Server was a master but lost all slaves. */
// Bits used by other monitors
#define SERVER_JOINED (1 << 19) /**<< The server is joined in a Galera cluster */
#define SERVER_MASTER_STICKINESS (1 << 20) /**<< Server Master stickiness */
inline bool status_is_connectable(uint64_t status)
{
return (status & (SERVER_RUNNING | SERVER_MAINT | SERVER_DRAINING)) == SERVER_RUNNING;
}
inline bool status_is_usable(uint64_t status)
{
return (status & (SERVER_RUNNING | SERVER_MAINT)) == SERVER_RUNNING;
}
inline bool status_is_running(uint64_t status)
{
return status & SERVER_RUNNING;
}
inline bool status_is_down(uint64_t status)
{
return (status & SERVER_RUNNING) == 0;
}
inline bool status_is_in_maint(uint64_t status)
{
return status & SERVER_MAINT;
}
inline bool status_is_draining(uint64_t status)
{
return status & SERVER_DRAINING;
}
inline bool status_is_master(uint64_t status)
{
return (status & (SERVER_RUNNING | SERVER_MASTER | SERVER_MAINT)) == (SERVER_RUNNING | SERVER_MASTER);
}
inline bool status_is_slave(uint64_t status)
{
return (status & (SERVER_RUNNING | SERVER_SLAVE | SERVER_MAINT)) == (SERVER_RUNNING | SERVER_SLAVE);
}
inline bool status_is_relay(uint64_t status)
{
return (status & (SERVER_RUNNING | SERVER_RELAY | SERVER_MAINT)) == (SERVER_RUNNING | SERVER_RELAY);
}
inline bool status_is_joined(uint64_t status)
{
return (status & (SERVER_RUNNING | SERVER_JOINED | SERVER_MAINT)) == (SERVER_RUNNING | SERVER_JOINED);
}
inline bool status_is_slave_of_ext_master(uint64_t status)
{
return (status & (SERVER_RUNNING | SERVER_SLAVE_OF_EXT_MASTER))
== (SERVER_RUNNING | SERVER_SLAVE_OF_EXT_MASTER);
}
inline bool status_is_disk_space_exhausted(uint64_t status)
{
return status & SERVER_DISK_SPACE_EXHAUSTED;
}
/**
* The SERVER structure defines a backend server. Each server has a name
* or IP address for the server, a port that the server listens on and
* the name of a protocol module that is loaded to implement the protocol
* between the gateway and the server.
*/
class SERVER
{
public:
static const int MAX_ADDRESS_LEN = 1024;
static const int MAX_MONUSER_LEN = 512;
static const int MAX_MONPW_LEN = 512;
static const int MAX_VERSION_LEN = 256;
static const int RLAG_UNDEFINED = -1; // Default replication lag value
// A mapping from a path to a percentage, e.g.: "/disk" -> 80.
typedef std::unordered_map<std::string, int32_t> DiskSpaceLimits;
enum class Type
{
MARIADB,
MYSQL,
XPAND
};
enum class RLagState
{
NONE,
BELOW_LIMIT,
ABOVE_LIMIT
};
struct Version
{
uint64_t total = 0; /**< The version number received from server */
uint32_t major = 0; /**< Major version */
uint32_t minor = 0; /**< Minor version */
uint32_t patch = 0; /**< Patch version */
};
/* Server connection and usage statistics */
struct ConnStats
{
uint64_t n_connections = 0; /**< Number of connections */
int n_current = 0; /**< Current connections */
int n_current_ops = 0; /**< Current active operations */
int n_persistent = 0; /**< Current persistent pool */
uint64_t n_new_conn = 0; /**< Times the current pool was empty */
uint64_t n_from_pool = 0; /**< Times when a connection was available from the pool */
uint64_t packets = 0; /**< Number of packets routed to this server */
};
// Base settings
char address[MAX_ADDRESS_LEN + 1] = {'\0'}; /**< Server hostname/IP-address */
int port = -1; /**< Server port */
int extra_port = -1; /**< Alternative monitor port if normal port fails */
// Other settings
bool proxy_protocol = false; /**< Send proxy-protocol header to backends when connecting
* routing sessions. */
// Base variables
bool is_active = false; /**< Server is active and has not been "destroyed" */
uint8_t charset = 0; /**< Character set. Read from backend and sent to client. As no character set
* has the numeric value of 0, it can be used to detect servers we haven't
* connected to. */
// Statistics and events
ConnStats stats; /**< The server statistics, e.g. number of connections */
int persistmax = 0; /**< Maximum pool size actually achieved since startup */
int last_event = 0; /**< The last event that occurred on this server */
int64_t triggered_at = 0; /**< Time when the last event was triggered */
// Status descriptors. Updated automatically by a monitor or manually by the admin
uint64_t status = 0; /**< Current status flag bitmap */
long node_id = -1; /**< Node id, server_id for M/S or local_index for Galera */
long master_id = -1; /**< Master server id of this node */
int rlag = RLAG_UNDEFINED;/**< Replication Lag for Master/Slave replication */
unsigned long node_ts = 0; /**< Last timestamp set from M/S monitor module */
// Misc fields
bool master_err_is_logged = false; /**< If node failed, this indicates whether it is logged. Only
* used by rwsplit. TODO: Move to rwsplit */
bool warn_ssl_not_enabled = true; /**< SSL not used for an SSL enabled server */
RLagState rlag_state = RLagState::NONE; /**< Is replication lag above or under limit? Used by rwsplit. */
virtual ~SERVER() = default;
/**
* Check if server has disk space threshold settings.
*
* @return True if limits exist
*/
virtual bool have_disk_space_limits() const = 0;
/**
* Get a copy of disk space limit settings.
*
* @return A copy of settings
*/
virtual DiskSpaceLimits get_disk_space_limits() const = 0;
/**
* Is persistent connection pool enabled.
*
* @return True if enabled
*/
virtual bool persistent_conns_enabled() const = 0;
/**
* Fetch value of custom parameter.
*
* @param name Parameter name
* @return Value of parameter, or empty if not found
*/
virtual std::string get_custom_parameter(const std::string& name) const = 0;
/**
* Update server version.
*
* @param version_num New numeric version
* @param version_str New version string
*/
virtual void set_version(uint64_t version_num, const std::string& version_str) = 0;
/**
* Get numeric version information.
*
* @return Major, minor and patch numbers
*/
virtual Version version() const = 0;
/**
* Get the type of the server.
*
* @return Server type
*/
virtual Type type() const = 0;
/**
* Get version string.
*
* @return Version string
*/
virtual std::string version_string() const = 0;
/**
* Returns the server configuration name. The value is returned as a c-string for printing convenience.
*
* @return Server name
*/
virtual const char* name() const = 0;
/**
* Get backend protocol module name.
*
* @return Backend protocol module name of the server
*/
virtual std::string protocol() const = 0;
/**
* Get server rank
*
* @return The server rank
*/
virtual int64_t rank() const = 0;
/*
* Update server address. TODO: Move this to internal class once blr is gone.
*
* @param address The new address
*/
bool server_update_address(const std::string& address);
/**
* Update the server port. TODO: Move this to internal class once blr is gone.
*
* @param new_port New port. The value is not checked but should generally be 1 -- 65535.
*/
void update_port(int new_port);
/**
* Update the server extra port. TODO: Move this to internal class once blr is gone.
*
* @param new_port New port. The value is not checked but should generally be 1 -- 65535.
*/
void update_extra_port(int new_port);
/**
* @brief Check if a server points to a local MaxScale service
*
* @return True if the server points to a local MaxScale service
*/
bool is_mxs_service();
/**
* Is the server valid and active? TODO: Rename once "is_active" is moved to internal class.
*
* @return True if server has not been removed from the runtime configuration.
*/
bool server_is_active() const
{
return is_active;
}
/**
* Is the server running and can be connected to?
*
* @return True if the server can be connected to.
*/
bool is_connectable() const
{
return status_is_connectable(status);
}
/**
* Is the server running and not in maintenance?
*
* @return True if server can be used.
*/
bool is_usable() const
{
return status_is_usable(status);
}
/**
* Is the server running?
*
* @return True if monitor can connect to the server.
*/
bool is_running() const
{
return status_is_running(status);
}
/**
* Is the server down?
*
* @return True if monitor cannot connect to the server.
*/
bool is_down() const
{
return status_is_down(status);
}
/**
* Is the server in maintenance mode?
*
* @return True if server is in maintenance.
*/
bool is_in_maint() const
{
return status_is_in_maint(status);
}
/**
* Is the server being drained?
*
* @return True if server is being drained.
*/
bool is_draining() const
{
return status_is_draining(status);
}
/**
* Is the server a master?
*
* @return True if server is running and marked as master.
*/
bool is_master() const
{
return status_is_master(status);
}
/**
* Is the server a slave.
*
* @return True if server is running and marked as slave.
*/
bool is_slave() const
{
return status_is_slave(status);
}
/**
* Is the server a relay slave?
*
* @return True, if server is a running relay.
*/
bool is_relay() const
{
return status_is_relay(status);
}
/**
* Is the server joined Galera node?
*
* @return True, if server is running and joined.
*/
bool is_joined() const
{
return status_is_joined(status);
}
bool is_in_cluster() const
{
return (status & (SERVER_MASTER | SERVER_SLAVE | SERVER_RELAY | SERVER_JOINED)) != 0;
}
bool is_slave_of_ext_master() const
{
return status_is_slave_of_ext_master(status);
}
bool is_low_on_disk_space() const
{
return status_is_disk_space_exhausted(status);
}
/**
* Find a server with the specified name.
*
* @param name Name of the server
* @return The server or NULL if not found
*/
static SERVER* find_by_unique_name(const std::string& name);
/**
* Find several servers with the names specified in an array. The returned array is equal in size
* to the server_names-array. If any server name was not found, then the corresponding element
* will be NULL.
*
* @param server_names An array of server names
* @return Array of servers
*/
static std::vector<SERVER*> server_find_by_unique_names(const std::vector<std::string>& server_names);
/**
* Convert the current server status flags to a string.
*
* @param server The server to return the status for
* @return A string representation of the status
*/
std::string status_string() const;
/**
* Convert a set of server status flags to a string.
*
* @param flags Status flags
* @param nConnections Number of current connections. Only affects the output
* if the @c SERVER_DRAINING bit is on. In that case, if
* the number of connections is 0 the state will be reported
* as 'Drained', otherwise as 'Draining'.
*
* @return A string representation of the status flags
*/
static std::string status_to_string(uint64_t flags, int nConnections = -1);
/**
* Convert a status string to a status bit. Only converts one status element.
*
* @param str String representation
* @return bit value or 0 on error
*/
static uint64_t status_from_string(const char* str);
/**
* Set a status bit in the server without locking
*
* @param bit The bit to set for the server
*/
void set_status(uint64_t bit);
/**
* Clear a status bit in the server without locking
*
* @param bit The bit to clear for the server
*/
void clear_status(uint64_t bit);
int response_time_num_samples() const
{
return m_response_time.num_samples();
}
double response_time_average() const
{
return m_response_time.average();
}
/**
* Add a response time measurement to the global server value.
*
* @param ave The value to add
* @param num_samples The weight of the new value, that is, the number of measurement points it represents
*/
void response_time_add(double ave, int num_samples);
const mxs::SSLProvider& ssl() const
{
return m_ssl_provider;
}
mxs::SSLProvider& ssl()
{
return m_ssl_provider;
}
protected:
SERVER(std::unique_ptr<mxs::SSLContext> ssl_context)
: m_response_time{0.04, 0.35, 500}
, m_ssl_provider{std::move(ssl_context)}
{
}
private:
maxbase::EMAverage m_response_time; /**< Response time calculations for this server */
std::mutex m_average_write_mutex; /**< Protects response time from concurrent writing */
mxs::SSLProvider m_ssl_provider;
};