RESTinio
connection_count_limiter.hpp
Go to the documentation of this file.
1 /*
2  * RESTinio
3  */
4 
11 #pragma once
12 
13 #include <restinio/null_mutex.hpp>
15 
17 
18 #include <cstdint>
19 #include <mutex>
20 #include <utility>
21 
22 namespace restinio
23 {
24 
25 namespace connection_count_limits
26 {
27 
28 //
29 // max_parallel_connections_t
30 //
32 
39  std::size_t, max_parallel_connections_tag >;
40 
41 //
42 // max_active_accepts_t
43 //
45 
52  std::size_t, max_active_accepts_tag >;
53 
54 namespace impl
55 {
56 
78 {
79 public:
84  virtual void
87  std::size_t index ) noexcept = 0;
88 
97  virtual void
100  std::size_t index ) noexcept = 0;
101 };
102 
114 template< typename Mutex_Type >
116 {
118  Mutex_Type m_lock;
119 
122 
138  std::size_t m_active_accepts{ 0u };
139 
146  std::size_t m_connections{ 0u };
147 
149  const std::size_t m_max_parallel_connections;
150 
165  std::vector< std::size_t > m_pending_indexes;
166 
168  bool
170  {
172  }
173 
174 public:
177  max_parallel_connections_t max_parallel_connections,
178  max_active_accepts_t max_pending_indexes )
179  : m_acceptor{ acceptor }
180  , m_max_parallel_connections{ max_parallel_connections.value() }
181  {
182  m_pending_indexes.reserve( max_pending_indexes.value() );
183  }
184 
185  actual_limiter_t( const actual_limiter_t & ) = delete;
187 
188  void
190  {
191  std::lock_guard< Mutex_Type > lock{ m_lock };
192 
193  // Expects that m_active_accepts is always greater than 0.
195 
196  ++m_connections;
197  }
198 
199  // Note: this method is noexcept because it can be called from
200  // destructors.
201  void
203  {
204  // Decrement active connections under acquired lock.
205  // If the count of connections drops below the limit and
206  // there are some pending indexes then one of them will
207  // be returned (wrapped into an optional).
208  auto index_to_activate = [this]() -> optional_t<std::size_t> {
209  std::lock_guard< Mutex_Type > lock{ m_lock };
210 
211  // Expects that m_connections is always greater than 0.
212  --m_connections;
213 
214  if( has_free_slots() && !m_pending_indexes.empty() )
215  {
216  std::size_t pending_index = m_pending_indexes.back();
217  m_pending_indexes.pop_back();
218  return pending_index;
219  }
220  else
221  return nullopt;
222  }();
223 
224  if( index_to_activate )
225  {
226  m_acceptor->schedule_next_accept_attempt( *index_to_activate );
227  }
228  }
229 
235  void
236  accept_next( std::size_t index ) noexcept
237  {
238  // Perform all operations under acquired lock.
239  // The result is a flag that tells can accept() be called right now.
240  const bool accept_now = [this, index]() -> bool {
241  std::lock_guard< Mutex_Type > lock{ m_lock };
242 
243  if( has_free_slots() )
244  {
246  return true;
247  }
248  else
249  {
250  m_pending_indexes.push_back( index );
251  return false;
252  }
253  }();
254 
255  if( accept_now )
256  {
257  m_acceptor->call_accept_now( index );
258  }
259  }
260 };
261 
262 } /* namespace impl */
263 
271 {
273 
274 public:
277  max_parallel_connections_t /*max_parallel_connections*/,
278  max_active_accepts_t /*max_pending_indexes*/ )
279  : m_acceptor{ acceptor }
280  {
281  }
282 
283  void
284  increment_parallel_connections() noexcept { /* Nothing to do */ }
285 
286  void
287  decrement_parallel_connections() noexcept { /* Nothing to do */ }
288 
293  void
294  accept_next( std::size_t index ) noexcept
295  {
296  m_acceptor->call_accept_now( index );
297  }
298 };
299 
309 template< typename Strand >
311 
321 template<>
323  : public connection_count_limits::impl::actual_limiter_t< null_mutex_t >
324 {
326 
327 public:
328  using base_t::base_t;
329 };
330 
340 template<>
343 {
345 
346 public:
347  using base_t::base_t;
348 };
349 
373 template< typename Count_Manager >
375 {
377 
378 public:
380  not_null_pointer_t< Count_Manager > manager ) noexcept
381  : m_manager{ manager }
382  {
383  m_manager->increment_parallel_connections();
384  }
385 
387  {
388  if( m_manager )
389  m_manager->decrement_parallel_connections();
390  }
391 
393  const connection_lifetime_monitor_t & ) = delete;
394 
395  friend void
398  connection_lifetime_monitor_t & b ) noexcept
399  {
400  using std::swap;
401  swap( a.m_manager, b.m_manager );
402  }
403 
405  connection_lifetime_monitor_t && other ) noexcept
406  : m_manager{ other.m_manager }
407  {
408  other.m_manager = nullptr;
409  }
410 
413  {
415  swap( *this, tmp );
416  return *this;
417  }
418 
421 };
422 
431 template<>
433 {
434 public:
437  {}
438 };
439 
440 } /* namespace connection_count_limits */
441 
457 template< typename Traits >
459 {
460  using limiter_t = typename std::conditional
461  <
462  Traits::use_connection_count_limiter,
464  typename Traits::strand_t >,
466  >::type;
467 
470 };
471 
472 } /* namespace restinio */
473 
restinio::connection_count_limits::connection_lifetime_monitor_t::m_manager
not_null_pointer_t< Count_Manager > m_manager
Definition: connection_count_limiter.hpp:376
tagged_scalar.hpp
Helper template for defining tagged scalar types.
restinio::connection_count_limits::noop_connection_count_limiter_t::increment_parallel_connections
void increment_parallel_connections() noexcept
Definition: connection_count_limiter.hpp:284
RESTINIO_NODISCARD
#define RESTINIO_NODISCARD
Definition: compiler_features.hpp:33
restinio::noop_strand_t
default_asio_executor noop_strand_t
A typedef for no-op strand type.
Definition: default_strands.hpp:28
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:421
restinio::connection_count_limits::connection_lifetime_monitor_t::connection_lifetime_monitor_t
connection_lifetime_monitor_t(connection_lifetime_monitor_t &&other) noexcept
Definition: connection_count_limiter.hpp:404
restinio::connection_count_limits::connection_lifetime_monitor_t
Helper type for controlling the lifetime of the connection.
Definition: connection_count_limiter.hpp:375
restinio::connection_count_limits::connection_lifetime_monitor_t< noop_connection_count_limiter_t >::connection_lifetime_monitor_t
connection_lifetime_monitor_t(not_null_pointer_t< noop_connection_count_limiter_t >) noexcept
Definition: connection_count_limiter.hpp:435
restinio::connection_count_limits::noop_connection_count_limiter_t::accept_next
void accept_next(std::size_t index) noexcept
Definition: connection_count_limiter.hpp:294
restinio::connection_count_limits::connection_count_limiter_t
Template class for connection count limiter for the case when connection count limit is actually used...
Definition: connection_count_limiter.hpp:310
restinio::connection_count_limits::impl::actual_limiter_t::has_free_slots
RESTINIO_NODISCARD bool has_free_slots() const noexcept
Definition: connection_count_limiter.hpp:169
restinio::connection_count_limits::connection_lifetime_monitor_t::connection_lifetime_monitor_t
connection_lifetime_monitor_t(not_null_pointer_t< Count_Manager > manager) noexcept
Definition: connection_count_limiter.hpp:379
restinio::connection_count_limits::impl::actual_limiter_t::accept_next
void accept_next(std::size_t index) noexcept
Definition: connection_count_limiter.hpp:236
restinio::connection_count_limits::impl::acceptor_callback_iface_t::schedule_next_accept_attempt
virtual void schedule_next_accept_attempt(std::size_t index) noexcept=0
restinio::connection_count_limit_types::limiter_t
typename std::conditional< Traits::use_connection_count_limiter, connection_count_limits::connection_count_limiter_t< typename Traits::strand_t >, connection_count_limits::noop_connection_count_limiter_t >::type limiter_t
Definition: connection_count_limiter.hpp:466
restinio::connection_count_limits::noop_connection_count_limiter_t
An implementation of connection count limiter for the case when connection count is not limited.
Definition: connection_count_limiter.hpp:271
restinio::connection_count_limits::connection_lifetime_monitor_t::swap
friend void swap(connection_lifetime_monitor_t &a, connection_lifetime_monitor_t &b) noexcept
Definition: connection_count_limiter.hpp:396
restinio::utils::tagged_scalar_t
Helper template for defining tagged scalar types.
Definition: tagged_scalar.hpp:54
restinio::connection_count_limits::impl::actual_limiter_t::m_connections
std::size_t m_connections
The counter of active connections.
Definition: connection_count_limiter.hpp:146
restinio::connection_count_limits::impl::acceptor_callback_iface_t::call_accept_now
virtual void call_accept_now(std::size_t index) noexcept=0
restinio::connection_count_limits::max_parallel_connections_tag
Definition: connection_count_limiter.hpp:31
restinio::connection_count_limits::impl::actual_limiter_t::m_acceptor
not_null_pointer_t< acceptor_callback_iface_t > m_acceptor
Mandatory pointer to the acceptor connected with this limiter.
Definition: connection_count_limiter.hpp:121
restinio::connection_count_limits::impl::acceptor_callback_iface_t
An interface of acceptor to be used by connection count limiters.
Definition: connection_count_limiter.hpp:78
restinio::connection_count_limits::impl::actual_limiter_t::actual_limiter_t
actual_limiter_t(const actual_limiter_t &)=delete
nonstd::optional_lite::optional
class optional
Definition: optional.hpp:839
restinio::not_null_pointer_t
T * not_null_pointer_t
Type for pointer that is not null by design.
Definition: common_types.hpp:150
restinio::connection_count_limits::noop_connection_count_limiter_t::noop_connection_count_limiter_t
noop_connection_count_limiter_t(not_null_pointer_t< connection_count_limits::impl::acceptor_callback_iface_t > acceptor, max_parallel_connections_t, max_active_accepts_t)
Definition: connection_count_limiter.hpp:275
restinio::connection_count_limits::impl::actual_limiter_t
Actual implementation of connection count limiter.
Definition: connection_count_limiter.hpp:116
nonstd::optional_lite::nullopt
const nullopt_t nullopt((nullopt_t::init()))
restinio::connection_count_limits::impl::actual_limiter_t::actual_limiter_t
actual_limiter_t(not_null_pointer_t< acceptor_callback_iface_t > acceptor, max_parallel_connections_t max_parallel_connections, max_active_accepts_t max_pending_indexes)
Definition: connection_count_limiter.hpp:175
restinio::connection_count_limits::impl::actual_limiter_t::actual_limiter_t
actual_limiter_t(actual_limiter_t &&)=delete
restinio::connection_count_limits::noop_connection_count_limiter_t::m_acceptor
not_null_pointer_t< connection_count_limits::impl::acceptor_callback_iface_t > m_acceptor
Definition: connection_count_limiter.hpp:272
restinio
Definition: asio_include.hpp:21
restinio::connection_count_limits::connection_lifetime_monitor_t::~connection_lifetime_monitor_t
~connection_lifetime_monitor_t()
Definition: connection_count_limiter.hpp:386
restinio::connection_count_limit_types
A kind of metafunction that deduces actual types related to connection count limiter in the dependecy...
Definition: connection_count_limiter.hpp:459
restinio::connection_count_limits::impl::actual_limiter_t::decrement_parallel_connections
void decrement_parallel_connections() noexcept
Definition: connection_count_limiter.hpp:202
restinio::connection_count_limits::impl::actual_limiter_t::m_pending_indexes
std::vector< std::size_t > m_pending_indexes
The storage for holding pending socket's slots.
Definition: connection_count_limiter.hpp:165
restinio::connection_count_limits::impl::actual_limiter_t::m_active_accepts
std::size_t m_active_accepts
The counter of active accept() operations.
Definition: connection_count_limiter.hpp:138
default_strands.hpp
Typedefs for default strands.
restinio::connection_count_limits::connection_lifetime_monitor_t::operator=
connection_lifetime_monitor_t & operator=(const connection_lifetime_monitor_t &)=delete
nonstd::optional_lite::swap
void swap(optional< T > &x, optional< T > &y)
Definition: optional.hpp:1619
restinio::connection_count_limits::impl::actual_limiter_t::m_max_parallel_connections
const std::size_t m_max_parallel_connections
The limit for parallel connections.
Definition: connection_count_limiter.hpp:149
restinio::connection_count_limits::impl::actual_limiter_t::m_lock
Mutex_Type m_lock
Lock object to be used.
Definition: connection_count_limiter.hpp:118
restinio::default_strand_t
asio_ns::strand< default_asio_executor > default_strand_t
A typedef for the default strand type.
Definition: default_strands.hpp:23
restinio::connection_count_limits::noop_connection_count_limiter_t::decrement_parallel_connections
void decrement_parallel_connections() noexcept
Definition: connection_count_limiter.hpp:287
restinio::connection_count_limits::impl::actual_limiter_t::increment_parallel_connections
void increment_parallel_connections() noexcept
Definition: connection_count_limiter.hpp:189
null_mutex.hpp
Definition of null_mutex.
restinio::connection_count_limits::connection_lifetime_monitor_t::operator=
connection_lifetime_monitor_t & operator=(connection_lifetime_monitor_t &&other) noexcept
Definition: connection_count_limiter.hpp:412
const
#define const
Definition: zconf.h:230
restinio::connection_count_limits::connection_lifetime_monitor_t::connection_lifetime_monitor_t
connection_lifetime_monitor_t(const connection_lifetime_monitor_t &)=delete
restinio::connection_count_limits::max_active_accepts_tag
Definition: connection_count_limiter.hpp:44