MySQL 9.2.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 <atomic>
42#include <chrono>
43#include <memory>
44
45#ifndef _WIN32
46#include <arpa/inet.h>
47#include <netdb.h>
48#include <netinet/in.h>
49#include <netinet/tcp.h>
50#include <sys/socket.h>
51#include <unistd.h>
52#else
53#include <windows.h>
54#include <winsock2.h>
55#include <ws2tcpip.h>
56#endif
57
58#include "connection.h"
60#include "context.h"
61#include "destination.h"
67#include "mysql/harness/plugin.h"
69#include "mysql_router_thread.h"
70#include "mysql_routing_base.h"
74#include "mysqlrouter/routing.h"
76#include "mysqlrouter/uri.h"
77#include "plugin_config.h"
79#include "socket_container.h"
80
81namespace mysql_harness {
82class PluginFuncEnv;
83} // namespace mysql_harness
84
85struct Nothing {};
86class MySQLRouting;
87
89 public:
91 const std::string &parent_routing_name)
92 : io_ctx_(io_ctx), parent_routing_name_(parent_routing_name) {}
93
95
98 virtual bool is_open() const = 0;
99
100 virtual void start(MySQLRouting *r, std::list<IoThread> &,
101 WaitableMonitor<Nothing> &waitable) = 0;
102
103 virtual std::string name() = 0;
104
106
107 protected:
109 // used when the acceptor logs
111};
112
114 public:
116 const std::string &parent_routing_name,
117 const std::string &address, uint16_t port);
118
121 bool is_open() const override;
122
123 void start(MySQLRouting *r, std::list<IoThread> &,
124 WaitableMonitor<Nothing> &waitable) override;
125
126 std::string name() override;
127
128 private:
131
132 std::string address_;
133 uint16_t port_;
134};
135
136#ifndef _WIN32
138 public:
140 const std::string &parent_routing_name,
141 const std::string &socket_name);
142
145 bool is_open() const override;
146
147 void start(MySQLRouting *r, std::list<IoThread> &,
148 WaitableMonitor<Nothing> &waitable) override;
149
150 std::string name() override;
151
152 private:
155
156 std::string socket_name_;
157};
158#endif
159
160/** @class MySQLRouting
161 * @brief Manage Connections from clients to MySQL servers
162 *
163 * The class MySQLRouter is used to start a service listening on a particular
164 * TCP port for incoming MySQL Client connection and route these to a MySQL
165 * Server.
166 */
168 public:
169 /** @brief Default constructor
170 *
171 * @param routing_config routing configuration
172 * @param io_ctx IO context
173 * @param guidelines routing guidelines engine
174 * @param route_name Name of connection routing (can be empty string)
175 * @param client_ssl_ctx SSL context of the client side
176 * @param dest_ssl_ctx SSL contexts of the destinations
177 */
179 const RoutingConfig &routing_config, net::io_context &io_ctx,
180 std::shared_ptr<routing_guidelines::Routing_guidelines_engine> guidelines,
181 const std::string &route_name = {},
182 TlsServerContext *client_ssl_ctx = nullptr,
183 DestinationTlsContext *dest_ssl_ctx = nullptr);
184
185 /** @brief Runs the service and accept incoming connections
186 *
187 * Runs the connection routing service and starts accepting incoming
188 * MySQL client connections.
189 *
190 * @throw std::runtime_error on errors.
191 *
192 */
194
195 void set_destinations(const std::string &dests);
196
197 /**
198 * Sets the destinations.
199 *
200 * @param dests destinations
201 */
202 void set_destinations_from_dests(
203 const std::vector<mysql_harness::Destination> &dests);
204
205 void set_destinations_from_uri(const mysqlrouter::URI &uri);
206
207 /** @brief Returns timeout when connecting to destination
208 *
209 * @return Timeout in seconds as int
210 */
211 std::chrono::milliseconds get_destination_connect_timeout() const noexcept {
212 return context_.get_destination_connect_timeout();
213 }
214
215 /** @brief Sets timeout when connecting to destination
216 *
217 * Checks timeout connecting with destination servers.
218 *
219 * @throw std::invalid_argument when an invalid value was provided.
220 *
221 * @param timeout Timeout
222 */
223 void validate_destination_connect_timeout(std::chrono::milliseconds timeout);
224
225 /** @brief Sets maximum active connections
226 *
227 * Sets maximum of active connections. Maximum must be between 1 and
228 * 65535.
229 *
230 * @throw std::invalid_argument when an invalid value was provided.
231 *
232 * @param maximum Max number of connections allowed
233 * @return New value as int
234 */
235 int set_max_connections(int maximum);
236
237 /** @brief Returns maximum active connections
238 *
239 * @return Maximum as int
240 */
241 int get_max_connections() const noexcept override { return max_connections_; }
242
243 /**
244 * create new connection to MySQL Server than can handle client's
245 * traffic and adds it to connection container.
246 *
247 * @param client_socket socket used to transfer data to/from client
248 * @param client_endpoint endpoint of client
249 */
250 template <class ClientProtocol>
251 void create_connection(
252 typename ClientProtocol::socket client_socket,
253 const typename ClientProtocol::endpoint &client_endpoint);
254
255 std::optional<routing::RoutingStrategy> get_routing_strategy()
256 const override {
257 return routing_strategy_;
258 }
259
260 std::vector<mysql_harness::Destination> get_destination_candidates()
261 const override;
262
263 std::vector<MySQLRoutingAPI::ConnData> get_connections() override;
264
265 MySQLRoutingConnectionBase *get_connection(const std::string &) override;
266
268 return destination_manager_.get();
269 }
270
271 void disconnect_all();
272
273 /**
274 * Stop accepting new connections on a listening socket.
275 *
276 * @param shutting_down is plugin shutting down.
277 */
278 void stop_socket_acceptors(const bool shutting_down) override;
279
280 /**
281 * Check if we are accepting connections on a routing socket.
282 *
283 * @retval true if we are accepting connections, false otherwise
284 */
285 bool is_accepting_connections() const override;
286
287 /**
288 * Start accepting new connections on a listening socket
289 *
290 * @returns std::string on errors.
291 */
292 stdx::expected<void, std::string> start_accepting_connections() override;
293
294 /**
295 * Start accepting new connections on a listening socket after it has been
296 * quarantined for lack of valid destinations
297 *
298 * @returns std::string on errors.
299 */
300 stdx::expected<void, std::string> restart_accepting_connections() override;
301
302 /**
303 * In case when routing guideline was updated go through each established
304 * connection and verify if it is allowed according to the new guideline. If
305 * not then such connection is dropped.
306 *
307 * @param affected_routing_sources list of routing guideline route names that
308 * were affected by the guideline update
309 */
310 void on_routing_guidelines_update(
312 &affected_routing_sources);
313
314 /**
315 * Try to update routing guideline with a new guideline.
316 *
317 * @return list of routing guideline route names that were affected by the
318 * guideline update
319 */
321 update_routing_guidelines(const std::string &routing_guidelines_document);
322
323 /**
324 * If the router info was updated then register this info in routing context.
325 *
326 * @param router_info updated router info
327 */
328 void on_router_info_update(
329 const routing_guidelines::Router_info &router_info);
330
331 bool is_standalone() const override { return is_destination_standalone_; }
332
333 private:
334 /** @brief Sets unix socket permissions so that the socket is accessible
335 * to all users (no-op on Windows)
336 * @param socket_file path to socket file
337 *
338 * @throw std::runtime_error if chmod() inside fails
339 */
340 static void set_unix_socket_permissions(const char *socket_file);
341
344
345 public:
346 MySQLRoutingContext &get_context() override { return context_; }
347
348 bool is_running() const override { return is_running_; }
349
350 /**
351 * get the purpose of connections to this route.
352 *
353 * - read-write : all statements are treated as "read-write".
354 * - read-only : all statements are treated as "read-only".
355 * - unavailable: it is currently unknown where the statement should go to.
356 *
357 * "Unavailable" is used for read-write splitting where the purpose is
358 * determined per statement, session, ...
359 *
360 * A statement over a read-only server connection may end up on a read-write
361 * server in case all read-only servers aren't reachable. Even if the server
362 * is read-write, the connections purpose is read-only and if the server
363 * changes its role from PRIMARY to SECONDARY, these read-only connections
364 * will not be abort as a SECONDARY is good enough to serve read-only
365 * connections.
366 */
367 mysqlrouter::ServerMode purpose() const override;
368
369 private:
370 /** Monitor for notifying socket acceptor */
371 WaitableMonitor<Nothing> acceptor_waitable_{Nothing{}};
372
373 /** @brief wrapper for data used by all connections */
375
377
378 /** @brief Destination object to use when getting next connection */
379 std::unique_ptr<DestinationManager> destination_manager_{nullptr};
380
381 bool is_destination_standalone_{false};
382
383 /** @brief Routing strategy to use when getting next destination */
384 std::optional<routing::RoutingStrategy> routing_strategy_;
385
386 /** @brief access_mode of the servers in the routing */
388
389 /** @brief Maximum active connections
390 *
391 * Maximum number of incoming connections that will be accepted
392 * by this MySQLRouter instances. There is no maximum for outgoing
393 * connections since it is one-to-one with incoming.
394 */
396
397 /** @brief used to unregister from subscription on allowed nodes changes */
399
400 /** @brief container for connections */
402
403 /** Information if the routing plugin is still running. */
404 std::atomic<bool> is_running_{true};
405
406 /** Used when the accepting port is been reopened and it failed, to schedule
407 * another retry for standalone-destination(s) route. */
408 net::steady_timer accept_port_reopen_retry_timer_{io_ctx_};
409
410#ifdef FRIEND_TEST
411 FRIEND_TEST(RoutingTests, bug_24841281);
412 FRIEND_TEST(RoutingTests, get_routing_thread_name);
413 FRIEND_TEST(ClassicProtocolRoutingTest, NoValidDestinations);
414 FRIEND_TEST(TestSetupTcpService, single_addr_ok);
415 FRIEND_TEST(TestSetupTcpService, getaddrinfo_fails);
416 FRIEND_TEST(TestSetupTcpService, socket_fails_for_all_addr);
417 FRIEND_TEST(TestSetupTcpService, socket_fails);
418 FRIEND_TEST(TestSetupTcpService, bind_fails);
419 FRIEND_TEST(TestSetupTcpService, listen_fails);
420#ifndef _WIN32
421 FRIEND_TEST(TestSetupTcpService, setsockopt_fails);
422 FRIEND_TEST(TestSetupNamedSocketService, unix_socket_permissions_failure);
423#endif
424#endif
425
426 std::vector<std::unique_ptr<AcceptingEndpoint>> accepting_endpoints_;
427};
428
429extern "C" {
430extern mysql_harness::Plugin ROUTING_PLUGIN_EXPORT harness_plugin_routing;
431}
432
433#endif // ROUTING_MYSQLROUTING_INCLUDED
Definition: mysql_routing.h:113
std::string address_
Definition: mysql_routing.h:132
uint16_t port_
Definition: mysql_routing.h:133
net::ip::tcp::acceptor service_
Definition: mysql_routing.h:129
net::ip::tcp::endpoint service_endpoint_
Definition: mysql_routing.h:130
Definition: mysql_routing.h:137
local::stream_protocol::acceptor service_
Definition: mysql_routing.h:153
std::string socket_name_
Definition: mysql_routing.h:156
local::stream_protocol::endpoint service_endpoint_
Definition: mysql_routing.h:154
Definition: mysql_routing.h:88
virtual ~AcceptingEndpoint()
Definition: mysql_routing.h:105
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:110
net::io_context & io_ctx_
Definition: mysql_routing.h:108
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:90
virtual stdx::expected< void, std::error_code > cancel()=0
container for connections to MySQL Server.
Definition: connection_container.h:164
Manage destinations for a Connection Routing.
Definition: destination.h:163
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:47
MySQLRoutingContext holds data used by MySQLRouting (1 per plugin instances) and MySQLRoutingConnecti...
Definition: context.h:54
Manage Connections from clients to MySQL servers.
Definition: mysql_routing.h:167
std::chrono::milliseconds get_destination_connect_timeout() const noexcept
Returns timeout when connecting to destination.
Definition: mysql_routing.h:211
bool is_standalone() const override
Definition: mysql_routing.h:331
MySQLRoutingContext & get_context() override
Definition: mysql_routing.h:346
std::optional< routing::RoutingStrategy > routing_strategy_
Routing strategy to use when getting next destination.
Definition: mysql_routing.h:384
ConnectionContainer connection_container_
container for connections
Definition: mysql_routing.h:401
routing::AccessMode access_mode_
access_mode of the servers in the routing
Definition: mysql_routing.h:387
std::optional< routing::RoutingStrategy > get_routing_strategy() const override
Definition: mysql_routing.h:255
AllowedNodesChangeCallbacksListIterator allowed_nodes_list_iterator_
used to unregister from subscription on allowed nodes changes
Definition: mysql_routing.h:398
std::vector< std::unique_ptr< AcceptingEndpoint > > accepting_endpoints_
Definition: mysql_routing.h:426
MySQLRoutingContext context_
wrapper for data used by all connections
Definition: mysql_routing.h:374
net::io_context & io_ctx_
Definition: mysql_routing.h:376
int max_connections_
Maximum active connections.
Definition: mysql_routing.h:395
bool is_running() const override
Definition: mysql_routing.h:348
DestinationManager * destination_manager()
Definition: mysql_routing.h:267
int get_max_connections() const noexcept override
Returns maximum active connections.
Definition: mysql_routing.h:241
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:66
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:644
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:44
ServerMode
Definition: datatypes.h:50
stdx::expected< native_handle_type, error_type > socket(int family, int sock_type, int protocol)
Definition: socket.h:63
AccessMode
Definition: routing.h:259
const mysql_service_registry_t * r
Definition: pfs_example_plugin_employee.cc:86
required uint64 port
Definition: replication_asynchronous_connection_failover.proto:33
AllowedNodesChangeCallbacksList::iterator AllowedNodesChangeCallbacksListIterator
Definition: destination.h:64
#define ROUTING_EXPORT
Definition: routing_export.h:15
#define ROUTING_PLUGIN_EXPORT
Definition: routing_plugin_export.h:15
case opt name
Definition: sslopt-case.h:29
Definition: mysql_routing.h:85
Information about this Router instance.
Definition: routing_guidelines.h:57
Type for names of Routes changed during routing guidelines document update.
Definition: routing_guidelines.h:322