MySQL 9.1.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
32
33/** @file
34 * @brief Defining the class MySQLRouting
35 *
36 * This file defines the main class `MySQLRouting` which is used to configure,
37 * start and manage a connection routing from clients and MySQL servers.
38 *
39 */
40
41#include <array>
42#include <atomic>
43#include <chrono>
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 /**
343 * get the purpose of connections to this route.
344 *
345 * - read-write : all statements are treated as "read-write".
346 * - read-only : all statements are treated as "read-only".
347 * - unavailable: it is currently unknown where the statement should go to.
348 *
349 * "Unavailable" is used for read-write splitting where the purpose is
350 * determined per statement, session, ...
351 *
352 * A statement over a read-only server connection may end up on a read-write
353 * server in case all read-only servers aren't reachable. Even if the server
354 * is read-write, the connections purpose is read-only and if the server
355 * changes its role from PRIMARY to SECONDARY, these read-only connections
356 * will not be abort as a SECONDARY is good enough to serve read-only
357 * connections.
358 */
359 mysqlrouter::ServerMode purpose() const override;
360
361 private:
362 /** Monitor for notifying socket acceptor */
363 WaitableMonitor<Nothing> acceptor_waitable_{Nothing{}};
364
365 /** @brief wrapper for data used by all connections */
367
369
370 /** @brief Destination object to use when getting next connection */
371 std::unique_ptr<RouteDestination> destination_;
372
373 bool is_destination_standalone_{false};
374
375 /** @brief Routing strategy to use when getting next destination */
377
378 /** @brief access_mode of the servers in the routing */
380
381 /** @brief Maximum active connections
382 *
383 * Maximum number of incoming connections that will be accepted
384 * by this MySQLRouter instances. There is no maximum for outgoing
385 * connections since it is one-to-one with incoming.
386 */
388
389 /** @brief used to unregister from subscription on allowed nodes changes */
391
392 /** @brief container for connections */
394
395 /** Information if the routing plugin is still running. */
396 std::atomic<bool> is_running_{true};
397
398 /** Used when the accepting port is been reopened and it failed, to schedule
399 * another retry for standalone-destination(s) route. */
400 net::steady_timer accept_port_reopen_retry_timer_{io_ctx_};
401
402#ifdef FRIEND_TEST
403 FRIEND_TEST(RoutingTests, bug_24841281);
404 FRIEND_TEST(RoutingTests, get_routing_thread_name);
405 FRIEND_TEST(ClassicProtocolRoutingTest, NoValidDestinations);
406 FRIEND_TEST(TestSetupTcpService, single_addr_ok);
407 FRIEND_TEST(TestSetupTcpService, getaddrinfo_fails);
408 FRIEND_TEST(TestSetupTcpService, socket_fails_for_all_addr);
409 FRIEND_TEST(TestSetupTcpService, socket_fails);
410 FRIEND_TEST(TestSetupTcpService, bind_fails);
411 FRIEND_TEST(TestSetupTcpService, listen_fails);
412#ifndef _WIN32
413 FRIEND_TEST(TestSetupTcpService, setsockopt_fails);
414 FRIEND_TEST(TestSetupNamedSocketService, unix_socket_permissions_failure);
415#endif
416#endif
417
418 std::vector<std::unique_ptr<AcceptingEndpoint>> accepting_endpoints_;
419};
420
421extern "C" {
422extern mysql_harness::Plugin ROUTING_PLUGIN_EXPORT harness_plugin_routing;
423}
424
425#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:371
MySQLRoutingContext & get_context() override
Definition: mysql_routing.h:338
ConnectionContainer connection_container_
container for connections
Definition: mysql_routing.h:393
routing::AccessMode access_mode_
access_mode of the servers in the routing
Definition: mysql_routing.h:379
AllowedNodesChangeCallbacksListIterator allowed_nodes_list_iterator_
used to unregister from subscription on allowed nodes changes
Definition: mysql_routing.h:390
std::vector< std::unique_ptr< AcceptingEndpoint > > accepting_endpoints_
Definition: mysql_routing.h:418
MySQLRoutingContext context_
wrapper for data used by all connections
Definition: mysql_routing.h:366
net::io_context & io_ctx_
Definition: mysql_routing.h:368
RouteDestination * destinations()
Definition: mysql_routing.h:294
int max_connections_
Maximum active connections.
Definition: mysql_routing.h:387
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:376
Manage destinations for a Connection Routing.
Definition: destination.h:189
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:286
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:199
mysql_harness::Plugin ROUTING_PLUGIN_EXPORT harness_plugin_routing
Definition: routing_plugin.cc:587
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
ServerMode
Definition: datatypes.h:50
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:71
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:65
case opt name
Definition: sslopt-case.h:29
Definition: mysql_routing.h:88