4#include "Stroika/Foundation/StroikaPreComp.h"
6#include "Stroika/Foundation/Containers/Collection.h"
10#include "ConnectionPool.h"
16using namespace Stroika::Foundation::IO;
22 using Options = Connection::Options;
28 struct DelegatingConnectionRepWithDeleteHook_ : Connection::IRep {
31 function<void (Ptr)> fDeleter;
33 DelegatingConnectionRepWithDeleteHook_ (
const Ptr& delegateTo, function<
void (Ptr)> deleter)
34 : fDelegateTo{delegateTo}
38 DelegatingConnectionRepWithDeleteHook_ (
const DelegatingConnectionRepWithDeleteHook_&) =
delete;
39 virtual ~DelegatingConnectionRepWithDeleteHook_ ()
41 fDeleter (fDelegateTo);
45 nonvirtual DelegatingConnectionRepWithDeleteHook_& operator= (
const DelegatingConnectionRepWithDeleteHook_&) =
delete;
48 virtual Options GetOptions ()
const override
50 return fDelegateTo.GetOptions ();
54 return fDelegateTo.GetTimeout ();
58 fDelegateTo.SetTimeout (timeout);
60 virtual URI GetSchemeAndAuthority ()
const override
64 virtual void SetSchemeAndAuthority (
const URI& schemeAndAuthority)
override
66 fDelegateTo.SetSchemeAndAuthority (schemeAndAuthority);
68 virtual void Close ()
override
74 return fDelegateTo.Send (request);
84ConnectionPool::Options::Options (
const optional<unsigned int>& maxConnections,
const function<
Connection::Ptr ()>& connectionFactory)
85 : fMaxConnections{maxConnections}
86 , fConnectionFactory{connectionFactory}
95class ConnectionPool::Rep_ {
99 Rep_ (
const Options& options)
105 Require (fOutstandingConnections == 0);
108 Connection::Ptr New (
const optional<Time::Duration>& timeout, optional<URI> hint, optional<AllocateGloballyIfTimeout> allocateGloballyOnTimeoutFlag)
121 optional<Connection::Ptr> poolEntryResult;
124 poolEntryResult = FindAndAllocateFromAvailableByURIMatch_ (hint->GetSchemeAndAuthority ());
126 if (not poolEntryResult) {
127 poolEntryResult = FindAndAllocateFromAvailable_ ();
129 if (not poolEntryResult) {
130 lock_guard critSec{fAvailableConnectionsChanged.fMutex};
131 size_t totalAllocated = fAvailableConnections.size () + fOutstandingConnections;
132 if (not fOptions.fMaxConnections or totalAllocated < *fOptions.fMaxConnections) {
133 fAvailableConnections += fOptions.fConnectionFactory ();
138 if (not poolEntryResult and Time::GetTickCount () < timeoutAt) {
140 unique_lock lock{fAvailableConnectionsChanged.fMutex};
141 if (fAvailableConnectionsChanged.wait_until (lock, Time::Pin2SafeSeconds (timeoutAt),
142 [
this] () { return not fAvailableConnections.empty (); })) {
146 if (not poolEntryResult) {
148 if (allocateGloballyOnTimeoutFlag) {
149 return fOptions.fConnectionFactory ();
156 return Connection::Ptr{Memory::MakeSharedPtr<DelegatingConnectionRepWithDeleteHook_> (
157 *poolEntryResult, [
this] (
const Ptr& p) { this->AddConnection_ (p); })};
159 optional<Connection::Ptr> FindAndAllocateFromAvailableByURIMatch_ (
const URI& matchScemeAndAuthority)
161 lock_guard critSec{fAvailableConnectionsChanged.fMutex};
162 for (
auto i = fAvailableConnections.begin (); i != fAvailableConnections.end (); ++i) {
163 if (i->GetSchemeAndAuthority () == matchScemeAndAuthority) {
165 fAvailableConnections.Remove (i);
166 ++fOutstandingConnections;
172 optional<Connection::Ptr> FindAndAllocateFromAvailable_ ()
174 lock_guard critSec{fAvailableConnectionsChanged.fMutex};
175 for (
auto i = fAvailableConnections.begin (); i != fAvailableConnections.end (); ++i) {
177 fAvailableConnections.Remove (i);
178 ++fOutstandingConnections;
185 lock_guard critSec{fAvailableConnectionsChanged.fMutex};
186 fAvailableConnections.Add (p);
187 --fOutstandingConnections;
188 fAvailableConnectionsChanged.notify_all ();
196 size_t fOutstandingConnections{};
207 : fRep_{make_unique<Rep_> (options)}
211ConnectionPool::~ConnectionPool ()
217 return fRep_->New (nullopt, hint, nullopt);
222 return fRep_->New (timeout, hint, nullopt);
227 return fRep_->New (timeout, hint, AllocateGloballyIfTimeout::eAllocateGloballyIfTimeout);
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
A Collection<T> is a container to manage an un-ordered collection of items, without equality defined ...
nonvirtual Connection::Ptr New(URI hint={})
ConnectionPool(const Options &options={})
nonvirtual URI GetSchemeAndAuthority() const
Duration is a chrono::duration<double> (=.
void ThrowError(error_code ec)
throw a SystemErrorException with the given error_code - or std::bad_alloc for errc::not_enough_memor...