connection_pool.hpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. //
  2. // Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_MYSQL_CONNECTION_POOL_HPP
  8. #define BOOST_MYSQL_CONNECTION_POOL_HPP
  9. #include <boost/mysql/any_connection.hpp>
  10. #include <boost/mysql/diagnostics.hpp>
  11. #include <boost/mysql/error_code.hpp>
  12. #include <boost/mysql/pool_params.hpp>
  13. #include <boost/mysql/with_diagnostics.hpp>
  14. #include <boost/mysql/detail/access.hpp>
  15. #include <boost/mysql/detail/config.hpp>
  16. #include <boost/mysql/detail/connection_pool_fwd.hpp>
  17. #include <boost/mysql/detail/initiation_base.hpp>
  18. #include <boost/asio/any_completion_handler.hpp>
  19. #include <boost/asio/any_io_executor.hpp>
  20. #include <boost/asio/async_result.hpp>
  21. #include <chrono>
  22. #include <memory>
  23. #include <utility>
  24. namespace boost {
  25. namespace mysql {
  26. /**
  27. * \brief A proxy to a connection owned by a pool that returns it to the pool when destroyed.
  28. * \details
  29. * A `pooled_connection` behaves like to a `std::unique_ptr`: it has exclusive ownership of an
  30. * \ref any_connection created by the pool. When destroyed, it returns the connection to the pool.
  31. * A `pooled_connection` may own nothing. We say such a connection is invalid (`this->valid() == false`).
  32. *
  33. * This class is movable but not copyable.
  34. *
  35. * \par Object lifetimes
  36. * While `*this` is alive, the \ref connection_pool internal data will be kept alive
  37. * automatically. It's safe to destroy the `connection_pool` object before `*this`.
  38. *
  39. * \par Thread safety
  40. * This object and the \ref any_connection object it may point to are **not thread safe**,
  41. * even if the connection pool used to obtain them was constructed with
  42. * \ref pool_params::thread_safe set to true.
  43. *
  44. * Functions that return the underlying connection to the pool
  45. * cause a mutation on the pool state object. Calling such functions
  46. * on objects obtained from the same pool
  47. * is thread-safe only if the pool was constructed with \ref pool_params::thread_safe set to true.
  48. *
  49. * In other words, individual connections can't be shared between threads. Pools can
  50. * be shared only if they're constructed with \ref pool_params::thread_safe set to true.
  51. *
  52. * - Distinct objects: safe if the \ref connection_pool that was used to obtain the objects
  53. * was created with \ref pool_params::thread_safe set to true. Otherwise, unsafe.
  54. * - Shared objects: always unsafe.
  55. */
  56. class pooled_connection
  57. {
  58. #ifndef BOOST_MYSQL_DOXYGEN
  59. friend struct detail::access;
  60. friend class detail::basic_pool_impl<any_connection, std::chrono::steady_clock, pooled_connection>;
  61. #endif
  62. struct impl_t
  63. {
  64. detail::connection_node* node;
  65. std::shared_ptr<detail::pool_impl> pool;
  66. } impl_{};
  67. pooled_connection(detail::connection_node& node, std::shared_ptr<detail::pool_impl> pool_impl) noexcept
  68. : impl_{&node, std::move(pool_impl)}
  69. {
  70. BOOST_ASSERT(impl_.pool);
  71. }
  72. public:
  73. /**
  74. * \brief Constructs an invalid pooled connection.
  75. * \details
  76. * The resulting object is invalid (`this->valid() == false`).
  77. *
  78. * \par Exception safety
  79. * No-throw guarantee.
  80. */
  81. pooled_connection() noexcept = default;
  82. /**
  83. * \brief Move constructor.
  84. * \details
  85. * Transfers connection ownership from `other` to `*this`.
  86. *
  87. * After this function returns, if `other.valid() == true`, `this->valid() == true`.
  88. * In any case, `other` will become invalid (`other.valid() == false`).
  89. *
  90. * \par Exception safety
  91. * No-throw guarantee.
  92. */
  93. pooled_connection(pooled_connection&& other) noexcept : impl_(std::move(other.impl_)) {}
  94. /**
  95. * \brief Move assignment.
  96. * \details
  97. * If `this->valid()`, returns the connection owned by `*this` to the pool and marks
  98. * it as pending reset (as if the destructor was called).
  99. * It then transfers connection ownership from `other` to `*this`.
  100. *
  101. * After this function returns, if `other.valid() == true`, `this->valid() == true`.
  102. * In any case, `other` will become invalid (`other.valid() == false`).
  103. *
  104. * \par Thread-safety
  105. * May cause a mutation on the connection pool that `this` points to.
  106. * Thread-safe for a shared pool only if it was constructed with
  107. * \ref pool_params::thread_safe set to true.
  108. *
  109. * \par Exception safety
  110. * No-throw guarantee.
  111. */
  112. pooled_connection& operator=(pooled_connection&& other) noexcept
  113. {
  114. if (valid())
  115. {
  116. detail::return_connection(*impl_.pool, *impl_.node, true);
  117. }
  118. impl_ = std::move(other.impl_);
  119. return *this;
  120. }
  121. #ifndef BOOST_MYSQL_DOXYGEN
  122. pooled_connection(const pooled_connection&) = delete;
  123. pooled_connection& operator=(const pooled_connection&) = delete;
  124. #endif
  125. /**
  126. * \brief Destructor.
  127. * \details
  128. * If `this->valid() == true`, returns the owned connection to the pool
  129. * and marks it as pending reset. If your connection doesn't need to be reset
  130. * (e.g. because you didn't mutate session state), use \ref return_without_reset.
  131. *
  132. * \par Thread-safety
  133. * May cause a mutation on the connection pool that `this` points to.
  134. * Thread-safe for a shared pool only if it was constructed with
  135. * \ref pool_params::thread_safe set to true.
  136. */
  137. ~pooled_connection()
  138. {
  139. if (valid())
  140. detail::return_connection(*impl_.pool, *impl_.node, true);
  141. }
  142. /**
  143. * \brief Returns whether the object owns a connection or not.
  144. * \par Exception safety
  145. * No-throw guarantee.
  146. */
  147. bool valid() const noexcept { return impl_.pool.get() != nullptr; }
  148. /**
  149. * \brief Retrieves the connection owned by this object.
  150. * \par Preconditions
  151. * The object should own a connection (`this->valid() == true`).
  152. *
  153. * \par Object lifetimes
  154. * The returned reference is valid as long as `*this` or an object
  155. * move-constructed or move-assigned from `*this` is alive.
  156. *
  157. * \par Exception safety
  158. * No-throw guarantee.
  159. */
  160. any_connection& get() noexcept { return detail::get_connection(*impl_.node); }
  161. /// \copydoc get
  162. const any_connection& get() const noexcept { return detail::get_connection(*impl_.node); }
  163. /// \copydoc get
  164. any_connection* operator->() noexcept { return &get(); }
  165. /// \copydoc get
  166. const any_connection* operator->() const noexcept { return &get(); }
  167. /**
  168. * \brief Returns the owned connection to the pool and marks it as not requiring reset.
  169. * \details
  170. * Returns a connection to the pool and marks it as idle. This will
  171. * skip the \ref any_connection::async_reset_connection call to wipe session state.
  172. * \n
  173. * This can provide a performance gain, but must be used with care. Failing to wipe
  174. * session state can lead to resource leaks (prepared statements not being released),
  175. * incorrect results and vulnerabilities (different logical operations interacting due
  176. * to leftover state).
  177. * \n
  178. * Please read the documentation on \ref any_connection::async_reset_connection before
  179. * calling this function. If in doubt, don't use it, and leave the destructor return
  180. * the connection to the pool for you.
  181. * \n
  182. * When this function returns, `*this` will own nothing (`this->valid() == false`).
  183. *
  184. * \par Preconditions
  185. * `this->valid() == true`
  186. *
  187. * \par Exception safety
  188. * No-throw guarantee.
  189. *
  190. * \par Thread-safety
  191. * Causes a mutation on the connection pool that `this` points to.
  192. * Thread-safe for a shared pool only if it was constructed with
  193. * \ref pool_params::thread_safe set to true.
  194. */
  195. void return_without_reset() noexcept
  196. {
  197. BOOST_ASSERT(valid());
  198. detail::return_connection(*impl_.pool, *impl_.node, false);
  199. impl_ = impl_t{};
  200. }
  201. };
  202. /**
  203. * \brief A pool of connections of variable size.
  204. * \details
  205. * A connection pool creates and manages \ref any_connection objects.
  206. * Using a pool allows to reuse sessions, avoiding part of the overhead associated
  207. * to session establishment. It also features built-in error handling and reconnection.
  208. * See the discussion and examples for more details on when to use this class.
  209. *
  210. * Connections are retrieved by \ref async_get_connection, which yields a
  211. * \ref pooled_connection object. They are returned to the pool when the
  212. * `pooled_connection` is destroyed, or by calling \ref pooled_connection::return_without_reset.
  213. *
  214. * A pool needs to be run before it can return any connection. Use \ref async_run for this.
  215. * Pools can only be run once.
  216. *
  217. * Connections are created, connected and managed internally by the pool, following
  218. * a well-defined state model. Please refer to the discussion for details.
  219. *
  220. * Due to oddities in Boost.Asio's universal async model, this class only
  221. * exposes async functions. You can use `asio::use_future` to transform them
  222. * into sync functions (please read the discussion for details).
  223. *
  224. * This is a move-only type.
  225. *
  226. * \par Default completion tokens
  227. * The default completion token for all async operations in this class is
  228. * `with_diagnostics(asio::deferred)`, which allows you to use `co_await`
  229. * and have the expected exceptions thrown on error.
  230. *
  231. * \par Thread-safety
  232. * Pools are composed of an internal state object, plus a handle to such state.
  233. * Each component has different thread-safety rules.
  234. *
  235. * Regarding **internal state**, connection pools are **not thread-safe by default**,
  236. * but can be made safe by constructing them with
  237. * \ref pool_params::thread_safe set to `true`.
  238. * Internal state is also mutated by some functions outside `connection_pool`, like
  239. * returning connections.
  240. *
  241. * The following actions imply a pool state mutation, and are protected by a strand
  242. * when thread-safety is enabled:
  243. *
  244. * - Calling \ref connection_pool::async_run.
  245. * - Calling \ref connection_pool::async_get_connection.
  246. * - Cancelling \ref async_get_connection by emitting a cancellation signal.
  247. * - Returning a connection by destroying a \ref pooled_connection or
  248. * calling \ref pooled_connection::return_without_reset.
  249. * - Cancelling the pool by calling \ref connection_pool::cancel,
  250. * emitting a cancellation signal for \ref async_run, or destroying the
  251. * `connection_pool` object.
  252. *
  253. * The **handle to the pool state** is **never thread-safe**, even for
  254. * pools with thread-safety enabled. Functions like assignments
  255. * modify the handle, and cause race conditions if called
  256. * concurrently with other functions. Other objects,
  257. * like \ref pooled_connection, have their own state handle,
  258. * and thus interact only with the pool state.
  259. *
  260. * If configured to be thread-safe, the protection applies only to the pool's state.
  261. * In particular, be careful when using `asio::cancel_after` and similar tokens.
  262. * Please read
  263. * <a href="../connection_pool.html#mysql.connection_pool.thread_safe">this page</a> for more info.
  264. *
  265. * In summary:
  266. *
  267. * - Distinct objects: safe. \n
  268. * - Shared objects: unsafe. Setting \ref pool_params::thread_safe
  269. * to `true` makes some functions safe.
  270. *
  271. * \par Object lifetimes
  272. * Connection pool objects create an internal state object that is referenced
  273. * by other objects and operations (like \ref pooled_connection). This object
  274. * will be kept alive using shared ownership semantics even after the `connection_pool`
  275. * object is destroyed. This results in intuitive lifetime rules.
  276. */
  277. class connection_pool
  278. {
  279. std::shared_ptr<detail::pool_impl> impl_;
  280. #ifndef BOOST_MYSQL_DOXYGEN
  281. friend struct detail::access;
  282. #endif
  283. struct initiate_run : detail::initiation_base
  284. {
  285. using detail::initiation_base::initiation_base;
  286. // Having diagnostics* here makes async_run compatible with with_diagnostics
  287. template <class Handler>
  288. void operator()(Handler&& h, diagnostics*, std::shared_ptr<detail::pool_impl> self)
  289. {
  290. async_run_erased(std::move(self), std::forward<Handler>(h));
  291. }
  292. };
  293. BOOST_MYSQL_DECL
  294. static void async_run_erased(
  295. std::shared_ptr<detail::pool_impl> pool,
  296. asio::any_completion_handler<void(error_code)> handler
  297. );
  298. struct initiate_get_connection : detail::initiation_base
  299. {
  300. using detail::initiation_base::initiation_base;
  301. template <class Handler>
  302. void operator()(Handler&& h, diagnostics* diag, std::shared_ptr<detail::pool_impl> self)
  303. {
  304. async_get_connection_erased(std::move(self), diag, std::forward<Handler>(h));
  305. }
  306. };
  307. BOOST_MYSQL_DECL
  308. static void async_get_connection_erased(
  309. std::shared_ptr<detail::pool_impl> pool,
  310. diagnostics* diag,
  311. asio::any_completion_handler<void(error_code, pooled_connection)> handler
  312. );
  313. template <class CompletionToken>
  314. auto async_get_connection_impl(diagnostics* diag, CompletionToken&& token)
  315. -> decltype(asio::async_initiate<CompletionToken, void(error_code, pooled_connection)>(
  316. std::declval<initiate_get_connection>(),
  317. token,
  318. diag,
  319. impl_
  320. ))
  321. {
  322. BOOST_ASSERT(valid());
  323. return asio::async_initiate<CompletionToken, void(error_code, pooled_connection)>(
  324. initiate_get_connection{get_executor()},
  325. token,
  326. diag,
  327. impl_
  328. );
  329. }
  330. BOOST_MYSQL_DECL
  331. connection_pool(asio::any_io_executor ex, pool_params&& params, int);
  332. public:
  333. /**
  334. * \brief Constructs a connection pool.
  335. * \details
  336. *
  337. * The pool is created in a "not-running" state. Call \ref async_run to transition to the
  338. * "running" state.
  339. *
  340. * The constructed pool is always valid (`this->valid() == true`).
  341. *
  342. * \par Executor
  343. * The passed executor becomes the pool executor, available through \ref get_executor.
  344. * `ex` is used as follows:
  345. *
  346. * - If `params.thread_safe == true`, `ex` is used to build a strand. The strand is used
  347. * to build internal I/O objects, like timers.
  348. * - If `params.thread_safe == false`, `ex` is used directly to build internal I/O objects.
  349. * - If `params.connection_executor` is empty, `ex` is used to build individual connections,
  350. * regardless of the chosen thread-safety mode. Otherwise, `params.connection_executor`
  351. * is used.
  352. *
  353. * \par Exception safety
  354. * Strong guarantee. Exceptions may be thrown by memory allocations.
  355. * \throws std::invalid_argument If `params` contains values that violate the rules described in \ref
  356. * pool_params.
  357. */
  358. connection_pool(asio::any_io_executor ex, pool_params params)
  359. : connection_pool(std::move(ex), std::move(params), 0)
  360. {
  361. }
  362. /**
  363. * \brief Constructs a connection pool.
  364. * \details
  365. * Equivalent to `connection_pool(ctx.get_executor(), params)`.
  366. *
  367. * This function participates in overload resolution only if `ExecutionContext`
  368. * satisfies the `ExecutionContext` requirements imposed by Boost.Asio.
  369. *
  370. * \par Exception safety
  371. * Strong guarantee. Exceptions may be thrown by memory allocations.
  372. * \throws std::invalid_argument If `params` contains values that violate the rules described in \ref
  373. * pool_params.
  374. */
  375. template <
  376. class ExecutionContext
  377. #ifndef BOOST_MYSQL_DOXYGEN
  378. ,
  379. class = typename std::enable_if<std::is_convertible<
  380. decltype(std::declval<ExecutionContext&>().get_executor()),
  381. asio::any_io_executor>::value>::type
  382. #endif
  383. >
  384. connection_pool(ExecutionContext& ctx, pool_params params)
  385. : connection_pool(ctx.get_executor(), std::move(params), 0)
  386. {
  387. }
  388. #ifndef BOOST_MYSQL_DOXYGEN
  389. connection_pool(const connection_pool&) = delete;
  390. connection_pool& operator=(const connection_pool&) = delete;
  391. #endif
  392. /**
  393. * \brief Move-constructor.
  394. * \details
  395. * Constructs a connection pool by taking ownership of `other`.
  396. *
  397. * After this function returns, if `other.valid() == true`, `this->valid() == true`.
  398. * In any case, `other` will become invalid (`other.valid() == false`).
  399. *
  400. * Moving a connection pool with outstanding async operations
  401. * is safe.
  402. *
  403. * \par Exception safety
  404. * No-throw guarantee.
  405. *
  406. * \par Thread-safety
  407. * Mutates `other`'s internal state handle. Does not access the pool state.
  408. * This function **can never be called concurrently with other functions
  409. * that read the internal state handle**, even for pools created
  410. * with \ref pool_params::thread_safe set to true.
  411. *
  412. * The internal pool state is not accessed, so this function can be called
  413. * concurrently with functions that only access the pool's internal state,
  414. * like returning connections.
  415. */
  416. connection_pool(connection_pool&& other) = default;
  417. /**
  418. * \brief Move assignment.
  419. * \details
  420. * Assigns `other` to `*this`, transferring ownership.
  421. *
  422. * After this function returns, if `other.valid() == true`, `this->valid() == true`.
  423. * In any case, `other` will become invalid (`other.valid() == false`).
  424. *
  425. * Moving a connection pool with outstanding async operations
  426. * is safe.
  427. *
  428. * \par Exception safety
  429. * No-throw guarantee.
  430. *
  431. * \par Thread-safety
  432. * Mutates `*this` and `other`'s internal state handle. Does not access the pool state.
  433. * This function **can never be called concurrently with other functions
  434. * that read the internal state handle**, even for pools created
  435. * with \ref pool_params::thread_safe set to true.
  436. *
  437. * The internal pool state is not accessed, so this function can be called
  438. * concurrently with functions that only access the pool's internal state,
  439. * like returning connections.
  440. */
  441. connection_pool& operator=(connection_pool&& other) = default;
  442. /**
  443. * \brief Destructor.
  444. * \details
  445. * Cancels all outstanding async operations on `*this`, as per \ref cancel.
  446. *
  447. * \par Thread-safety
  448. * Mutates the internal state handle. Mutates the pool state.
  449. * This function **can never be called concurrently with other functions
  450. * that read the internal state handle**, even for pools created
  451. * with \ref pool_params::thread_safe set to true.
  452. *
  453. * The internal pool state is modified as per \ref cancel.
  454. * If thread-safety is enabled, it's safe to call the destructor concurrently
  455. * with functions that only access the pool's internal state,
  456. * like returning connections.
  457. */
  458. ~connection_pool()
  459. {
  460. if (valid())
  461. cancel();
  462. }
  463. /**
  464. * \brief Returns whether the object is in a moved-from state.
  465. * \details
  466. * This function returns always `true` except for pools that have been
  467. * moved-from. Moved-from objects don't represent valid pools. They can only
  468. * be assigned to or destroyed.
  469. *
  470. * \par Exception safety
  471. * No-throw guarantee.
  472. *
  473. * \par Thread-safety
  474. * Reads the internal state handle. Does not access the pool state.
  475. * Can be called concurrently with any other function that reads the state handle,
  476. * like \ref async_run or \ref async_get_connection.
  477. * It can't be called concurrently with functions modifying the handle, like assignments,
  478. * even if \ref pool_params::thread_safe is set to true.
  479. */
  480. bool valid() const noexcept { return impl_.get() != nullptr; }
  481. /// The executor type associated to this object.
  482. using executor_type = asio::any_io_executor;
  483. /**
  484. * \brief Retrieves the executor associated to this object.
  485. * \details
  486. * Returns the executor used to construct the pool as first argument.
  487. * This is the case even when using \ref pool_params::thread_safe -
  488. * the internal strand created in this case is never exposed.
  489. *
  490. * \par Exception safety
  491. * No-throw guarantee.
  492. *
  493. * \par Thread-safety
  494. * Reads the internal state handle. Reads the pool state.
  495. * If the pool was built with thread-safety enabled, it can be called
  496. * concurrently with other functions that don't modify the state handle.
  497. */
  498. BOOST_MYSQL_DECL
  499. executor_type get_executor() noexcept;
  500. /**
  501. * \brief Runs the pool task in charge of managing connections.
  502. * \details
  503. * This function creates and connects new connections, and resets and pings
  504. * already created ones. You need to call this function for \ref async_get_connection
  505. * to succeed.
  506. *
  507. * The async operation will run indefinitely, until the pool is cancelled
  508. * (by calling \ref cancel or using per-operation cancellation on the `async_run` operation).
  509. * The operation completes once all internal connection operations
  510. * (including connects, pings and resets) complete.
  511. *
  512. * It is safe to call this function after calling \ref cancel.
  513. *
  514. * \par Preconditions
  515. * This function can be called at most once for a single pool.
  516. * Formally, `async_run` hasn't been called before on `*this` or any object
  517. * used to move-construct or move-assign `*this`.
  518. *
  519. * Additionally, `this->valid() == true`.
  520. *
  521. * \par Object lifetimes
  522. * While the operation is outstanding, the pool's internal data will be kept alive.
  523. * It is safe to destroy `*this` while the operation is outstanding.
  524. *
  525. * \par Handler signature
  526. * The handler signature for this operation is `void(boost::mysql::error_code)`
  527. *
  528. * \par Executor
  529. *
  530. * The final handler is executed using `token`'s associated executor,
  531. * or `this->get_executor()` if the token doesn't have an associated
  532. * executor. The final handler is called as if it was submitted using `asio::post`,
  533. * and is never be called inline from within this function.
  534. *
  535. * If the pool was constructed with thread-safety enabled, intermediate
  536. * completion handlers are executed using an internal strand that wraps `this->get_executor()`.
  537. * Otherwise, intermediate handlers are executed using `this->get_executor()`.
  538. * In any case, the token's associated executor is only used for the final handler.
  539. *
  540. * \par Per-operation cancellation
  541. * This operation supports per-operation cancellation. Cancelling `async_run`
  542. * is equivalent to calling \ref connection_pool::cancel.
  543. * The following `asio::cancellation_type_t` values are supported:
  544. *
  545. * - `asio::cancellation_type_t::terminal`
  546. * - `asio::cancellation_type_t::partial`
  547. *
  548. * Note that `asio::cancellation_type_t::total` is not supported because invoking
  549. * `async_run` always has observable side effects.
  550. *
  551. * \par Errors
  552. * This function always complete successfully. The handler signature ensures
  553. * maximum compatibility with Boost.Asio infrastructure.
  554. *
  555. * \par Thread-safety
  556. * Reads the internal state handle. Mutates the pool state.
  557. * If the pool was built with thread-safety enabled, it can be called
  558. * concurrently with other functions that don't modify the state handle.
  559. */
  560. template <
  561. BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code))
  562. CompletionToken = with_diagnostics_t<asio::deferred_t>>
  563. auto async_run(CompletionToken&& token = {})
  564. BOOST_MYSQL_RETURN_TYPE(decltype(asio::async_initiate<CompletionToken, void(error_code)>(
  565. std::declval<initiate_run>(),
  566. token,
  567. static_cast<diagnostics*>(nullptr),
  568. impl_
  569. )))
  570. {
  571. BOOST_ASSERT(valid());
  572. return asio::async_initiate<CompletionToken, void(error_code)>(
  573. initiate_run{get_executor()},
  574. token,
  575. static_cast<diagnostics*>(nullptr),
  576. impl_
  577. );
  578. }
  579. /**
  580. * \brief Retrieves a connection from the pool.
  581. * \details
  582. * Retrieves an idle connection from the pool to be used.
  583. *
  584. * If this function completes successfully (empty error code), the return \ref pooled_connection
  585. * will have `valid() == true` and will be usable. If it completes with a non-empty error code,
  586. * it will have `valid() == false`.
  587. *
  588. * If a connection is idle when the operation is started, it will complete immediately
  589. * with that connection. Otherwise, it will wait for a connection to become idle
  590. * (possibly creating one in the process, if pool configuration allows it), until
  591. * the operation is cancelled (by emitting a cancellation signal) or the pool
  592. * is cancelled (by calling \ref connection_pool::cancel).
  593. * If the pool is not running, the operation fails immediately.
  594. *
  595. * If the operation is cancelled, and the overload with \ref diagnostics was used,
  596. * the output diagnostics will contain the most recent error generated by
  597. * the connections attempting to connect (via \ref any_connection::async_connect), if any.
  598. * In cases where \ref async_get_connection doesn't complete because connections are unable
  599. * to connect, this feature can help figuring out where the problem is.
  600. *
  601. * \par Preconditions
  602. * `this->valid() == true` \n
  603. *
  604. * \par Object lifetimes
  605. * While the operation is outstanding, the pool's internal data will be kept alive.
  606. * It is safe to destroy `*this` while the operation is outstanding.
  607. *
  608. * \par Handler signature
  609. * The handler signature for this operation is
  610. * `void(boost::mysql::error_code, boost::mysql::pooled_connection)`
  611. *
  612. * \par Executor
  613. *
  614. * If the final handler has an associated immediate executor, and the operation
  615. * completes immediately, the final handler is dispatched to it.
  616. * Otherwise, the final handler is called as if it was submitted using `asio::post`,
  617. * and is never be called inline from within this function.
  618. * Immediate completions can only happen when thread-safety is not enabled.
  619. *
  620. * The final handler is executed using `token`'s associated executor,
  621. * or `this->get_executor()` if the token doesn't have an associated
  622. * executor.
  623. *
  624. * If the pool was constructed with thread-safety enabled, intermediate
  625. * completion handlers are executed using an internal strand that wraps `this->get_executor()`.
  626. * Otherwise, intermediate handlers are executed using
  627. * `token`'s associated executor if it has one, or `this->get_executor()` if it hasn't.
  628. *
  629. * **Caution**: be careful when using thread-safety and `asio::cancel_after`, as it
  630. * can result in inadvertent race conditions. Please refer to
  631. * <a href="../../../connection_pool.html#mysql.connection_pool.thread_safe">this
  632. * page</a> for more info.
  633. *
  634. * \par Per-operation cancellation
  635. * This operation supports per-operation cancellation.
  636. * Cancelling `async_get_connection` has no observable side effects.
  637. * The following `asio::cancellation_type_t` values are supported:
  638. *
  639. * - `asio::cancellation_type_t::terminal`
  640. * - `asio::cancellation_type_t::partial`
  641. * - `asio::cancellation_type_t::total`
  642. *
  643. * \par Errors
  644. * - \ref client_errc::no_connection_available, if the `async_get_connection`
  645. * operation is cancelled before a connection becomes available.
  646. * - \ref client_errc::pool_not_running, if the `async_get_connection`
  647. * operation is cancelled before async_run is called.
  648. * - \ref client_errc::pool_cancelled, if the pool is cancelled before
  649. * the operation completes, or `async_get_connection` is called
  650. * on a pool that has been cancelled.
  651. *
  652. * \par Thread-safety
  653. * Reads the internal state handle. Mutates the pool state.
  654. * If the pool was built with thread-safety enabled, it can be called
  655. * concurrently with other functions that don't modify the state handle.
  656. */
  657. template <
  658. BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::pooled_connection))
  659. CompletionToken = with_diagnostics_t<asio::deferred_t>>
  660. auto async_get_connection(CompletionToken&& token = {}) BOOST_MYSQL_RETURN_TYPE(
  661. decltype(async_get_connection_impl(nullptr, std::forward<CompletionToken>(token)))
  662. )
  663. {
  664. return async_get_connection_impl(nullptr, std::forward<CompletionToken>(token));
  665. }
  666. /// \copydoc async_get_connection
  667. template <
  668. BOOST_ASIO_COMPLETION_TOKEN_FOR(void(::boost::mysql::error_code, ::boost::mysql::pooled_connection))
  669. CompletionToken = with_diagnostics_t<asio::deferred_t>>
  670. auto async_get_connection(diagnostics& diag, CompletionToken&& token = {}) BOOST_MYSQL_RETURN_TYPE(
  671. decltype(async_get_connection_impl(nullptr, std::forward<CompletionToken>(token)))
  672. )
  673. {
  674. return async_get_connection_impl(&diag, std::forward<CompletionToken>(token));
  675. }
  676. /**
  677. * \brief Stops any current outstanding operation and marks the pool as cancelled.
  678. * \details
  679. * This function has the following effects:
  680. *
  681. * \li Stops the currently outstanding \ref async_run operation, if any, which will complete
  682. * with a success error code.
  683. * \li Cancels any outstanding \ref async_get_connection operations.
  684. * \li Marks the pool as cancelled. Successive `async_get_connection` calls will
  685. * fail immediately.
  686. *
  687. * This function will return immediately, without waiting for the cancelled operations to complete.
  688. *
  689. * You may call this function any number of times. Successive calls will have no effect.
  690. *
  691. * \par Preconditions
  692. * `this->valid() == true`
  693. *
  694. * \par Exception safety
  695. * Basic guarantee. Memory allocations and acquiring mutexes may throw.
  696. *
  697. * \par Thread-safety
  698. * Reads the internal state handle. Mutates the pool state.
  699. * If the pool was built with thread-safety enabled, it can be called
  700. * concurrently with other functions that don't modify the state handle.
  701. */
  702. BOOST_MYSQL_DECL
  703. void cancel();
  704. };
  705. } // namespace mysql
  706. } // namespace boost
  707. #ifdef BOOST_MYSQL_HEADER_ONLY
  708. #include <boost/mysql/impl/connection_pool.ipp>
  709. #endif
  710. #endif