connection_pool.hpp 28 KB

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