connection_count_limiter.hpp
Go to the documentation of this file.
/*
* RESTinio
*/
#pragma once
#include <restinio/null_mutex.hpp>
#include <restinio/default_strands.hpp>
#include <restinio/utils/tagged_scalar.hpp>
#include <cstdint>
#include <mutex>
#include <utility>
namespace restinio
{
namespace connection_count_limits
{
//
// max_parallel_connections_t
//
struct max_parallel_connections_tag {};
using max_parallel_connections_t = restinio::utils::tagged_scalar_t<
std::size_t, max_parallel_connections_tag >;
//
// max_active_accepts_t
//
struct max_active_accepts_tag {};
using max_active_accepts_t = restinio::utils::tagged_scalar_t<
std::size_t, max_active_accepts_tag >;
namespace impl
{
class acceptor_callback_iface_t
{
public:
virtual void
call_accept_now(
std::size_t index ) noexcept = 0;
virtual void
schedule_next_accept_attempt(
std::size_t index ) noexcept = 0;
};
template< typename Mutex_Type >
class actual_limiter_t
{
Mutex_Type m_lock;
not_null_pointer_t< acceptor_callback_iface_t > m_acceptor;
std::size_t m_active_accepts{ 0u };
std::size_t m_connections{ 0u };
const std::size_t m_max_parallel_connections;
std::vector< std::size_t > m_pending_indexes;
RESTINIO_NODISCARD
bool
has_free_slots() const noexcept
{
return (m_active_accepts + m_connections) < m_max_parallel_connections;
}
public:
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 )
: m_acceptor{ acceptor }
, m_max_parallel_connections{ max_parallel_connections.value() }
{
m_pending_indexes.reserve( max_pending_indexes.value() );
}
actual_limiter_t( const actual_limiter_t & ) = delete;
actual_limiter_t( actual_limiter_t && ) = delete;
void
increment_parallel_connections() noexcept
{
std::lock_guard< Mutex_Type > lock{ m_lock };
// Expects that m_active_accepts is always greater than 0.
--m_active_accepts;
++m_connections;
}
// Note: this method is noexcept because it can be called from
// destructors.
void
decrement_parallel_connections() noexcept
{
// Decrement active connections under acquired lock.
// If the count of connections drops below the limit and
// there are some pending indexes then one of them will
// be returned (wrapped into an optional).
auto index_to_activate = [this]() -> optional_t<std::size_t> {
std::lock_guard< Mutex_Type > lock{ m_lock };
// Expects that m_connections is always greater than 0.
--m_connections;
if( has_free_slots() && !m_pending_indexes.empty() )
{
std::size_t pending_index = m_pending_indexes.back();
m_pending_indexes.pop_back();
return pending_index;
}
else
return nullopt;
}();
if( index_to_activate )
{
m_acceptor->schedule_next_accept_attempt( *index_to_activate );
}
}
void
accept_next( std::size_t index ) noexcept
{
// Perform all operations under acquired lock.
// The result is a flag that tells can accept() be called right now.
const bool accept_now = [this, index]() -> bool {
std::lock_guard< Mutex_Type > lock{ m_lock };
if( has_free_slots() )
{
++m_active_accepts;
return true;
}
else
{
m_pending_indexes.push_back( index );
return false;
}
}();
if( accept_now )
{
m_acceptor->call_accept_now( index );
}
}
};
} /* namespace impl */
class noop_connection_count_limiter_t
{
not_null_pointer_t< connection_count_limits::impl::acceptor_callback_iface_t > m_acceptor;
public:
noop_connection_count_limiter_t(
not_null_pointer_t< connection_count_limits::impl::acceptor_callback_iface_t > acceptor,
max_parallel_connections_t /*max_parallel_connections*/,
max_active_accepts_t /*max_pending_indexes*/ )
: m_acceptor{ acceptor }
{
}
void
increment_parallel_connections() noexcept { /* Nothing to do */ }
void
decrement_parallel_connections() noexcept { /* Nothing to do */ }
void
accept_next( std::size_t index ) noexcept
{
m_acceptor->call_accept_now( index );
}
};
template< typename Strand >
class connection_count_limiter_t;
template<>
class connection_count_limiter_t< noop_strand_t >
: public connection_count_limits::impl::actual_limiter_t< null_mutex_t >
{
using base_t = connection_count_limits::impl::actual_limiter_t< null_mutex_t >;
public:
using base_t::base_t;
};
template<>
class connection_count_limiter_t< default_strand_t >
: public connection_count_limits::impl::actual_limiter_t< std::mutex >
{
using base_t = connection_count_limits::impl::actual_limiter_t< std::mutex >;
public:
using base_t::base_t;
};
template< typename Count_Manager >
class connection_lifetime_monitor_t
{
not_null_pointer_t< Count_Manager > m_manager;
public:
connection_lifetime_monitor_t(
not_null_pointer_t< Count_Manager > manager ) noexcept
: m_manager{ manager }
{
m_manager->increment_parallel_connections();
}
~connection_lifetime_monitor_t()
{
if( m_manager )
m_manager->decrement_parallel_connections();
}
connection_lifetime_monitor_t(
const connection_lifetime_monitor_t & ) = delete;
friend void
swap(
connection_lifetime_monitor_t & a,
connection_lifetime_monitor_t & b ) noexcept
{
using std::swap;
swap( a.m_manager, b.m_manager );
}
connection_lifetime_monitor_t(
connection_lifetime_monitor_t && other ) noexcept
: m_manager{ other.m_manager }
{
other.m_manager = nullptr;
}
connection_lifetime_monitor_t &
operator=( connection_lifetime_monitor_t && other ) noexcept
{
connection_lifetime_monitor_t tmp{ std::move(other) };
swap( *this, tmp );
return *this;
}
connection_lifetime_monitor_t &
operator=( const connection_lifetime_monitor_t & ) = delete;
};
template<>
class connection_lifetime_monitor_t< noop_connection_count_limiter_t >
{
public:
connection_lifetime_monitor_t(
not_null_pointer_t< noop_connection_count_limiter_t > ) noexcept
{}
};
} /* namespace connection_count_limits */
template< typename Traits >
struct connection_count_limit_types
{
using 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;
using lifetime_monitor_t =
connection_count_limits::connection_lifetime_monitor_t< limiter_t >;
};
} /* namespace restinio */
nonstd::optional_lite::optional
class optional
Definition: optional.hpp:919
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::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::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::operator=
connection_lifetime_monitor_t & operator=(connection_lifetime_monitor_t &&other) noexcept
Definition: connection_count_limiter.hpp:412
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_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::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::operator=
connection_lifetime_monitor_t & operator=(const connection_lifetime_monitor_t &)=delete
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::connection_lifetime_monitor_t::m_manager
not_null_pointer_t< Count_Manager > m_manager
Definition: connection_count_limiter.hpp:376
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::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::acceptor_callback_iface_t::schedule_next_accept_attempt
virtual void schedule_next_accept_attempt(std::size_t index) noexcept=0
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::impl::actual_limiter_t
Actual implementation of connection count limiter.
Definition: connection_count_limiter.hpp:116
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
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::connection_count_limits::impl::actual_limiter_t::actual_limiter_t
actual_limiter_t(actual_limiter_t &&)=delete
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::has_free_slots
RESTINIO_NODISCARD bool has_free_slots() const noexcept
Definition: connection_count_limiter.hpp:169
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::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(const actual_limiter_t &)=delete
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::increment_parallel_connections
void increment_parallel_connections() noexcept
Definition: connection_count_limiter.hpp:189
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::actual_limiter_t::accept_next
void accept_next(std::size_t index) noexcept
Definition: connection_count_limiter.hpp:236
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::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::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::noop_connection_count_limiter_t::increment_parallel_connections
void increment_parallel_connections() noexcept
Definition: connection_count_limiter.hpp:284
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::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::utils::tagged_scalar_t
Helper template for defining tagged scalar types.
Definition: tagged_scalar.hpp:54
restinio::utils::tagged_scalar_t::value
RESTINIO_NODISCARD constexpr Scalar value() const noexcept
Definition: tagged_scalar.hpp:67
RESTINIO_NODISCARD
#define RESTINIO_NODISCARD
Definition: compiler_features.hpp:33
default_strands.hpp
Typedefs for default strands.
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:465
nonstd::optional_lite::nullopt
const nullopt_t nullopt((nullopt_t::init()))
nonstd::optional_lite::swap
void swap(optional< T > &x, optional< T > &y)
Definition: optional.hpp:1705
restinio
Definition: asio_include.hpp:21
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::not_null_pointer_t
T * not_null_pointer_t
Type for pointer that is not null by design.
Definition: common_types.hpp:169
restinio::noop_strand_t
default_asio_executor noop_strand_t
A typedef for no-op strand type.
Definition: default_strands.hpp:28
null_mutex.hpp
Definition of null_mutex.
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_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::max_active_accepts_tag
Definition: connection_count_limiter.hpp:44
restinio::connection_count_limits::max_parallel_connections_tag
Definition: connection_count_limiter.hpp:31
tagged_scalar.hpp
Helper template for defining tagged scalar types.
const
#define const
Definition: zconf.h:230