File indexing completed on 2025-12-13 09:54:56
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MYSQL_IMPL_INTERNAL_CONNECTION_POOL_SANSIO_CONNECTION_NODE_HPP
0009 #define BOOST_MYSQL_IMPL_INTERNAL_CONNECTION_POOL_SANSIO_CONNECTION_NODE_HPP
0010
0011 #include <boost/mysql/diagnostics.hpp>
0012 #include <boost/mysql/error_code.hpp>
0013
0014 #include <boost/asio/error.hpp>
0015 #include <boost/assert.hpp>
0016
0017 #include <algorithm>
0018 #include <cstddef>
0019
0020 namespace boost {
0021 namespace mysql {
0022 namespace detail {
0023
0024
0025 enum class node_status
0026 {
0027
0028
0029 initial,
0030
0031
0032 connect_in_progress,
0033
0034
0035 sleep_connect_failed_in_progress,
0036
0037
0038 reset_in_progress,
0039
0040
0041 ping_in_progress,
0042
0043
0044 idle,
0045
0046
0047 in_use,
0048
0049
0050 terminated,
0051 };
0052
0053
0054
0055 enum class next_connection_action
0056 {
0057
0058 none,
0059
0060
0061 connect,
0062
0063
0064 sleep_connect_failed,
0065
0066
0067 idle_wait,
0068
0069
0070 reset,
0071
0072
0073 ping,
0074 };
0075
0076
0077
0078 enum class collection_state
0079 {
0080
0081 none,
0082
0083
0084 needs_collect,
0085
0086
0087 needs_collect_with_reset
0088 };
0089
0090
0091
0092 template <class Derived>
0093 class sansio_connection_node
0094 {
0095 node_status status_;
0096
0097 inline bool is_pending(node_status status) noexcept
0098 {
0099 return status != node_status::initial && status != node_status::idle &&
0100 status != node_status::in_use && status != node_status::terminated;
0101 }
0102
0103 inline static next_connection_action status_to_action(node_status status) noexcept
0104 {
0105 switch (status)
0106 {
0107 case node_status::connect_in_progress: return next_connection_action::connect;
0108 case node_status::sleep_connect_failed_in_progress:
0109 return next_connection_action::sleep_connect_failed;
0110 case node_status::ping_in_progress: return next_connection_action::ping;
0111 case node_status::reset_in_progress: return next_connection_action::reset;
0112 case node_status::idle:
0113 case node_status::in_use: return next_connection_action::idle_wait;
0114 default: return next_connection_action::none;
0115 }
0116 }
0117
0118 next_connection_action set_status(node_status new_status)
0119 {
0120 auto& derived = static_cast<Derived&>(*this);
0121
0122
0123 if (new_status == node_status::idle && status_ != node_status::idle)
0124 derived.entering_idle();
0125 else if (new_status != node_status::idle && status_ == node_status::idle)
0126 derived.exiting_idle();
0127
0128
0129 if (!is_pending(status_) && is_pending(new_status))
0130 derived.entering_pending();
0131 else if (is_pending(status_) && !is_pending(new_status))
0132 derived.exiting_pending();
0133
0134
0135 status_ = new_status;
0136
0137 return status_to_action(new_status);
0138 }
0139
0140 public:
0141 sansio_connection_node(node_status initial_status = node_status::initial) noexcept
0142 : status_(initial_status)
0143 {
0144 }
0145
0146 void mark_as_in_use() noexcept
0147 {
0148 BOOST_ASSERT(status_ == node_status::idle);
0149 set_status(node_status::in_use);
0150 }
0151
0152 void cancel() { set_status(node_status::terminated); }
0153
0154 next_connection_action resume(error_code ec, collection_state col_st)
0155 {
0156 switch (status_)
0157 {
0158 case node_status::initial: return set_status(node_status::connect_in_progress);
0159 case node_status::connect_in_progress:
0160 return ec ? set_status(node_status::sleep_connect_failed_in_progress)
0161 : set_status(node_status::idle);
0162 case node_status::sleep_connect_failed_in_progress:
0163 return set_status(node_status::connect_in_progress);
0164 case node_status::idle:
0165
0166
0167 return set_status(node_status::ping_in_progress);
0168 case node_status::in_use:
0169
0170
0171
0172 if (col_st == collection_state::needs_collect)
0173 {
0174
0175 return set_status(node_status::idle);
0176 }
0177 else if (col_st == collection_state::needs_collect_with_reset)
0178 {
0179 return set_status(node_status::reset_in_progress);
0180 }
0181 else
0182 {
0183
0184
0185 return next_connection_action::idle_wait;
0186 }
0187 case node_status::ping_in_progress:
0188 case node_status::reset_in_progress:
0189
0190 return ec ? set_status(node_status::connect_in_progress) : set_status(node_status::idle);
0191 case node_status::terminated:
0192 default: return next_connection_action::none;
0193 }
0194 }
0195
0196
0197 node_status status() const noexcept { return status_; }
0198 };
0199
0200
0201
0202 inline diagnostics create_connect_diagnostics(error_code connect_ec, const diagnostics& connect_diag)
0203 {
0204 diagnostics res;
0205 if (connect_ec)
0206 {
0207
0208
0209 auto& res_impl = access::get_impl(res);
0210 const auto& connect_diag_impl = access::get_impl(connect_diag);
0211
0212 if (connect_ec == asio::error::operation_aborted)
0213 {
0214
0215 res_impl.msg = "Last connection attempt timed out";
0216 res_impl.is_server = false;
0217 }
0218 else
0219 {
0220
0221 res_impl.msg = "Last connection attempt failed with: ";
0222 res_impl.msg += connect_ec.message();
0223 res_impl.msg += " [";
0224 res_impl.msg += connect_ec.to_string();
0225 res_impl.msg += "]";
0226
0227
0228 if (connect_diag_impl.msg.empty())
0229 {
0230
0231 res_impl.is_server = false;
0232 }
0233 else
0234 {
0235
0236 res_impl.msg += ": ";
0237 res_impl.msg += connect_diag_impl.msg;
0238 res_impl.is_server = connect_diag_impl.is_server;
0239 }
0240 }
0241 }
0242 return res;
0243 }
0244
0245
0246
0247 inline std::size_t num_connections_to_create(
0248 std::size_t initial_size,
0249 std::size_t max_size,
0250 std::size_t current_connections,
0251 std::size_t pending_connections,
0252 std::size_t pending_requests
0253 )
0254 {
0255 BOOST_ASSERT(initial_size <= max_size);
0256 BOOST_ASSERT(current_connections <= max_size);
0257 BOOST_ASSERT(pending_connections <= current_connections);
0258
0259
0260
0261 std::size_t required_by_requests = pending_requests > pending_connections
0262 ? static_cast<std::size_t>(pending_requests - pending_connections)
0263 : 0u;
0264
0265
0266
0267 std::size_t required_by_min = current_connections < initial_size
0268 ? static_cast<std::size_t>(initial_size - current_connections)
0269 : 0u;
0270
0271
0272 std::size_t room = static_cast<std::size_t>(max_size - current_connections);
0273
0274 return (std::min)((std::max)(required_by_requests, required_by_min), room);
0275 }
0276
0277 }
0278 }
0279 }
0280
0281 #endif