MySQL 8.4.0
Source Code Documentation
mysql_routing.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2015, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef ROUTING_MYSQLROUTING_INCLUDED
27#define ROUTING_MYSQLROUTING_INCLUDED
28
31
32/** @file
33 * @brief Defining the class MySQLRouting
34 *
35 * This file defines the main class `MySQLRouting` which is used to configure,
36 * start and manage a connection routing from clients and MySQL servers.
37 *
38 */
39
40#include <array>
41#include <atomic>
42#include <chrono>
43#include <iostream>
44#include <map>
45#include <memory>
46#include <mutex>
47#include <stdexcept>
48
49#ifndef _WIN32
50#include <arpa/inet.h>
51#include <netdb.h>
52#include <netinet/in.h>
53#include <netinet/tcp.h>
54#include <sys/socket.h>
55#include <unistd.h>
56#else
57#include <windows.h>
58#include <winsock2.h>
59#include <ws2tcpip.h>
60#endif
61
62#include "connection.h"
64#include "context.h"
65#include "destination.h"
71#include "mysql/harness/plugin.h"
73#include "mysql_router_thread.h"
74#include "mysql_routing_base.h"
77#include "mysqlrouter/routing.h"
79#include "mysqlrouter/uri.h"
80#include "plugin_config.h"
81#include "socket_container.h"
82#include "tcp_address.h"
83
84namespace mysql_harness {
85class PluginFuncEnv;
86} // namespace mysql_harness
87
88struct Nothing {};
89class MySQLRouting;
90
92 public:
94 const std::string &parent_routing_name)
95 : io_ctx_(io_ctx), parent_routing_name_(parent_routing_name) {}
96
98
101 virtual bool is_open() const = 0;
102
103 virtual void start(MySQLRouting *r, std::list<IoThread> &,
104 WaitableMonitor<Nothing> &waitable) = 0;
105
106 virtual std::string name() = 0;
107
109
110 protected:
112 // used when the acceptor logs
114};
115
117 public:
119 const std::string &parent_routing_name,
120 const std::string &address, uint16_t port);
121
124 bool is_open() const override;
125
126 void start(MySQLRouting *r, std::list<IoThread> &,
127 WaitableMonitor<Nothing> &waitable) override;
128
129 std::string name() override;
130
131 private:
134
135 std::string address_;
136 uint16_t port_;
137};
138
139#ifndef _WIN32
141 public:
143 const std::string &parent_routing_name,
144 const std::string &socket_name);
145
148 bool is_open() const override;
149
150 void start(MySQLRouting *r, std::list<IoThread> &,
151 WaitableMonitor<Nothing> &waitable) override;
152
153 std::string name() override;
154
155 private:
158
159 std::string socket_name_;
160};
161#endif
162
163/** @class MySQLRouting
164 * @brief Manage Connections from clients to MySQL servers
165 *
166 * The class MySQLRouter is used to start a service listening on a particular
167 * TCP port for incoming MySQL Client connection and route these to a MySQL
168 * Server.
169 *
170 * Connection routing will not analyze or parse any MySQL package (except from
171 * those in the handshake phase to be able to discover invalid connection
172 * error) nor will it do any authentication. It will not handle errors from the
173 * MySQL server and not automatically recover. The client communicate through
174 * MySQL Router just like it would directly connecting.
175 *
176 * The MySQL Server is chosen from a given list of hosts or IP addresses
177 * (with or without TCP port) based on the the mode. For example, mode
178 * read-only will go through the list of servers in a round-robin way. The
179 * mode read-write will always go through the list from the beginning and
180 * failover to the next available.
181 *
182 *
183 * Example usage: bind to all IP addresses and use TCP Port 7001
184 *
185 * @code
186 * MySQLRouting r(conf, ioctx);
187 * r.destination_connect_timeout = std::chrono::seconds(1);
188 * r.set_destinations_from_csv("10.0.10.5;10.0.11.6");
189 * r.run();
190 * @endcode
191 *
192 * The above example will, when MySQL running on 10.0.10.5 is not available,
193 * use 10.0.11.6 to setup the connection routing.
194 *
195 */
197 public:
198 /** @brief Default constructor
199 *
200 * @param routing_config routing configuration
201 * @param io_ctx IO context
202 * @param route_name Name of connection routing (can be empty string)
203 * @param client_ssl_ctx SSL context of the client side
204 * @param dest_ssl_ctx SSL contexts of the destinations
205 */
206 MySQLRouting(const RoutingConfig &routing_config, net::io_context &io_ctx,
207 const std::string &route_name = {},
208 TlsServerContext *client_ssl_ctx = nullptr,
209 DestinationTlsContext *dest_ssl_ctx = nullptr);
210
211 /** @brief Runs the service and accept incoming connections
212 *
213 * Runs the connection routing service and starts accepting incoming
214 * MySQL client connections.
215 *
216 * @throw std::runtime_error on errors.
217 *
218 */
220
221 /** @brief Sets the destinations from URI
222 *
223 * Sets destinations using the given string and the given mode. The string
224 * should be a comma separated list of MySQL servers.
225 *
226 * The mode is one of MySQLRouting::Mode, for example
227 * MySQLRouting::Mode::kReadOnly.
228 *
229 * Example of destinations:
230 * "10.0.10.5,10.0.11.6:3307"
231 *
232 * @param csv destinations as comma-separated-values
233 */
234 void set_destinations_from_csv(const std::string &csv);
235
236 void set_destinations_from_uri(const mysqlrouter::URI &uri);
237
238 /** @brief Returns timeout when connecting to destination
239 *
240 * @return Timeout in seconds as int
241 */
242 std::chrono::milliseconds get_destination_connect_timeout() const noexcept {
243 return context_.get_destination_connect_timeout();
244 }
245
246 /** @brief Sets timeout when connecting to destination
247 *
248 * Checks timeout connecting with destination servers.
249 *
250 * @throw std::invalid_argument when an invalid value was provided.
251 *
252 * @param timeout Timeout
253 */
254 void validate_destination_connect_timeout(std::chrono::milliseconds timeout);
255
256 /** @brief Sets maximum active connections
257 *
258 * Sets maximum of active connections. Maximum must be between 1 and
259 * 65535.
260 *
261 * @throw std::invalid_argument when an invalid value was provided.
262 *
263 * @param maximum Max number of connections allowed
264 * @return New value as int
265 */
266 int set_max_connections(int maximum);
267
268 /** @brief Returns maximum active connections
269 *
270 * @return Maximum as int
271 */
272 int get_max_connections() const noexcept override { return max_connections_; }
273
274 /**
275 * create new connection to MySQL Server than can handle client's
276 * traffic and adds it to connection container.
277 *
278 * @param client_socket socket used to transfer data to/from client
279 * @param client_endpoint endpoint of client
280 */
281 template <class ClientProtocol>
282 void create_connection(
283 typename ClientProtocol::socket client_socket,
284 const typename ClientProtocol::endpoint &client_endpoint);
285
287
288 std::vector<mysql_harness::TCPAddress> get_destinations() const override;
289
290 std::vector<MySQLRoutingAPI::ConnData> get_connections() override;
291
292 MySQLRoutingConnectionBase *get_connection(const std::string &) override;
293
294 RouteDestination *destinations() { return destination_.get(); }
295
296 void disconnect_all();
297
298 /**
299 * Stop accepting new connections on a listening socket.
300 */
301 void stop_socket_acceptors() override;
302
303 /**
304 * Check if we are accepting connections on a routing socket.
305 *
306 * @retval true if we are accepting connections, false otherwise
307 */
308 bool is_accepting_connections() const override;
309
310 /**
311 * Start accepting new connections on a listening socket
312 *
313 * @returns std::string on errors.
314 */
315 stdx::expected<void, std::string> start_accepting_connections() override;
316
317 /**
318 * Start accepting new connections on a listening socket after it has been
319 * quarantined for lack of valid destinations
320 *
321 * @returns std::string on errors.
322 */
323 stdx::expected<void, std::string> restart_accepting_connections() override;
324
325 private:
326 /** @brief Sets unix socket permissions so that the socket is accessible
327 * to all users (no-op on Windows)
328 * @param socket_file path to socket file
329 *
330 * @throw std::runtime_error if chmod() inside fails
331 */
332 static void set_unix_socket_permissions(const char *socket_file);
333
336
337 public:
338 MySQLRoutingContext &get_context() override { return context_; }
339
340 bool is_running() const override { return is_running_; }
341
342 private:
343 /** Monitor for notifying socket acceptor */
344 WaitableMonitor<Nothing> acceptor_waitable_{Nothing{}};
345
346 /** @brief wrapper for data used by all connections */
348
350
351 /** @brief Destination object to use when getting next connection */
352 std::unique_ptr<RouteDestination> destination_;
353
354 bool is_destination_standalone_{false};
355
356 /** @brief Routing strategy to use when getting next destination */
358
359 /** @brief access_mode of the servers in the routing */
361
362 /** @brief Maximum active connections
363 *
364 * Maximum number of incoming connections that will be accepted
365 * by this MySQLRouter instances. There is no maximum for outgoing
366 * connections since it is one-to-one with incoming.
367 */
369
370 /** @brief used to unregister from subscription on allowed nodes changes */
372
373 /** @brief container for connections */
375
376 /** Information if the routing plugin is still running. */
377 std::atomic<bool> is_running_{true};
378
379 /** Used when the accepting port is been reopened and it failed, to schedule
380 * another retry for standalone-destination(s) route. */
381 net::steady_timer accept_port_reopen_retry_timer_{io_ctx_};
382
383#ifdef FRIEND_TEST
384 FRIEND_TEST(RoutingTests, bug_24841281);
385 FRIEND_TEST(RoutingTests, get_routing_thread_name);
386 FRIEND_TEST(ClassicProtocolRoutingTest, NoValidDestinations);
387 FRIEND_TEST(TestSetupTcpService, single_addr_ok);
388 FRIEND_TEST(TestSetupTcpService, getaddrinfo_fails);
389 FRIEND_TEST(TestSetupTcpService, socket_fails_for_all_addr);
390 FRIEND_TEST(TestSetupTcpService, socket_fails);
391 FRIEND_TEST(TestSetupTcpService, bind_fails);
392 FRIEND_TEST(TestSetupTcpService, listen_fails);
393#ifndef _WIN32
394 FRIEND_TEST(TestSetupTcpService, setsockopt_fails);
395 FRIEND_TEST(TestSetupNamedSocketService, unix_socket_permissions_failure);
396#endif
397#endif
398
399 std::vector<std::unique_ptr<AcceptingEndpoint>> accepting_endpoints_;
400};
401
402extern "C" {
403extern mysql_harness::Plugin ROUTING_PLUGIN_EXPORT harness_plugin_routing;
404}
405
406#endif // ROUTING_MYSQLROUTING_INCLUDED
Definition: mysql_routing.h:116
std::string address_
Definition: mysql_routing.h:135
uint16_t port_
Definition: mysql_routing.h:136
net::ip::tcp::acceptor service_
Definition: mysql_routing.h:132
net::ip::tcp::endpoint service_endpoint_
Definition: mysql_routing.h:133
Definition: mysql_routing.h:140
local::stream_protocol::acceptor service_
Definition: mysql_routing.h:156
std::string socket_name_
Definition: mysql_routing.h:159
local::stream_protocol::endpoint service_endpoint_
Definition: mysql_routing.h:157
Definition: mysql_routing.h:91
virtual ~AcceptingEndpoint()
Definition: mysql_routing.h:108
virtual stdx::expected< void, std::error_code > setup()=0
virtual void start(MySQLRouting *r, std::list< IoThread > &, WaitableMonitor< Nothing > &waitable)=0
virtual std::string name()=0
std::string parent_routing_name_
Definition: mysql_routing.h:113
net::io_context & io_ctx_
Definition: mysql_routing.h:111
AcceptingEndpoint(const AcceptingEndpoint &)=delete
virtual bool is_open() const =0
AcceptingEndpoint(net::io_context &io_ctx, const std::string &parent_routing_name)
Definition: mysql_routing.h:93
virtual stdx::expected< void, std::error_code > cancel()=0
container for connections to MySQL Server.
Definition: connection_container.h:167
TlsClientContext per destination.
Definition: destination_ssl_context.h:42
Facade to avoid a tight coupling between Routing component and actual routing endpoint implementation...
Definition: mysql_routing_base.h:41
Definition: connection.h:44
MySQLRoutingContext holds data used by MySQLRouting (1 per plugin instances) and MySQLRoutingConnecti...
Definition: context.h:59
Manage Connections from clients to MySQL servers.
Definition: mysql_routing.h:196
std::chrono::milliseconds get_destination_connect_timeout() const noexcept
Returns timeout when connecting to destination.
Definition: mysql_routing.h:242
std::unique_ptr< RouteDestination > destination_
Destination object to use when getting next connection.
Definition: mysql_routing.h:352
MySQLRoutingContext & get_context() override
Definition: mysql_routing.h:338
ConnectionContainer connection_container_
container for connections
Definition: mysql_routing.h:374
routing::AccessMode access_mode_
access_mode of the servers in the routing
Definition: mysql_routing.h:360
AllowedNodesChangeCallbacksListIterator allowed_nodes_list_iterator_
used to unregister from subscription on allowed nodes changes
Definition: mysql_routing.h:371
std::vector< std::unique_ptr< AcceptingEndpoint > > accepting_endpoints_
Definition: mysql_routing.h:399
MySQLRoutingContext context_
wrapper for data used by all connections
Definition: mysql_routing.h:347
net::io_context & io_ctx_
Definition: mysql_routing.h:349
RouteDestination * destinations()
Definition: mysql_routing.h:294
int max_connections_
Maximum active connections.
Definition: mysql_routing.h:368
bool is_running() const override
Definition: mysql_routing.h:340
int get_max_connections() const noexcept override
Returns maximum active connections.
Definition: mysql_routing.h:272
routing::RoutingStrategy routing_strategy_
Routing strategy to use when getting next destination.
Definition: mysql_routing.h:357
Manage destinations for a Connection Routing.
Definition: destination.h:188
virtual mysql_harness::TCPAddress get(const std::string &address, uint16_t port)
Gets destination based on address and port.
Definition: destination.cc:131
route specific configuration.
Definition: routing_config.h:40
TLS Context for the server side.
Definition: tls_server_context.h:51
Monitor can be waited for.
Definition: monitor.h:62
PluginFuncEnv object.
Definition: loader.h:673
Parse and create URIs according to RFC3986.
Definition: uri.h:70
Definition: socket.h:1293
Definition: timer.h:57
Definition: io_context.h:61
Definition: internet.h:678
Definition: expected.h:284
static int get_connection(MEM_ROOT *mem_root, FEDERATED_SHARE *share)
Definition: ha_federated.cc:608
static void start(mysql_harness::PluginFuncEnv *env)
Definition: http_auth_backend_plugin.cc:180
static void run(mysql_harness::PluginFuncEnv *)
Definition: io_plugin.cc:197
mysql_harness::Plugin ROUTING_PLUGIN_EXPORT harness_plugin_routing
Definition: routing_plugin.cc:591
std::string get_routing_thread_name(const std::string &config_name, const std::string &prefix)
return a short string suitable to be used as a thread name
Definition: mysql_routing_common.cc:30
static bool timeout(bool(*wait_condition)())
Timeout function.
Definition: log0meb.cc:498
Definition: common.h:42
stdx::expected< native_handle_type, error_type > socket(int family, int sock_type, int protocol)
Definition: socket.h:63
RoutingStrategy get_routing_strategy(const std::string &value)
Returns RoutingStrategy for its literal representation.
Definition: routing.cc:87
AccessMode
Definition: routing.h:259
RoutingStrategy
Routing strategies supported by Routing plugin.
Definition: routing.h:265
const mysql_service_registry_t * r
Definition: pfs_example_plugin_employee.cc:86
required uint64 port
Definition: replication_asynchronous_connection_failover.proto:33
#define ROUTING_EXPORT
Definition: routing_export.h:15
#define ROUTING_PLUGIN_EXPORT
Definition: routing_plugin_export.h:15
AllowedNodesChangeCallbacksList::iterator AllowedNodesChangeCallbacksListIterator
Definition: destination.h:64
case opt name
Definition: sslopt-case.h:29
Definition: mysql_routing.h:88