#pragma once #include #include #include #include #include #include #include "http_common.h" namespace NNeh { namespace NHttp2 { // TConn must be refcounted and contain methods: // void SetCached(bool) noexcept // bool IsValid() const noexcept // void Close() noexcept template class TConnCache { struct TCounter : TAtomicCounter { inline void IncCount(const TConn* const&) { Inc(); } inline void DecCount(const TConn* const&) { Dec(); } }; public: typedef TIntrusivePtr TConnRef; class TConnList: public TLockFreeQueue { public: ~TConnList() { Clear(); } inline void Clear() { TConn* conn; while (this->Dequeue(&conn)) { conn->Close(); conn->UnRef(); } } inline size_t Size() { return this->GetCounter().Val(); } }; inline void Put(TConnRef& conn, size_t addrId) { conn->SetCached(true); ConnList(addrId).Enqueue(conn.Get()); conn->Ref(); Y_UNUSED(conn.Release()); CachedConn_.Inc(); } bool Get(TConnRef& conn, size_t addrId) { TConnList& connList = ConnList(addrId); TConn* connTmp; while (connList.Dequeue(&connTmp)) { connTmp->SetCached(false); CachedConn_.Dec(); if (connTmp->IsValid()) { TConnRef(connTmp).Swap(conn); connTmp->DecRef(); return true; } else { connTmp->UnRef(); } } return false; } inline size_t Size() const noexcept { return CachedConn_.Val(); } inline size_t Validate(size_t addrId) { TConnList& cl = Lst_.Get(addrId); return Validate(cl); } //close/remove part of the connections from cache size_t Purge(size_t addrId, size_t frac256) { TConnList& cl = Lst_.Get(addrId); size_t qsize = cl.Size(); if (!qsize) { return 0; } size_t purgeCounter = ((qsize * frac256) >> 8); if (!purgeCounter && qsize >= 2) { purgeCounter = 1; } size_t pc = 0; { TConn* conn; while (purgeCounter-- && cl.Dequeue(&conn)) { conn->SetCached(false); if (conn->IsValid()) { conn->Close(); } CachedConn_.Dec(); conn->UnRef(); ++pc; } } pc += Validate(cl); return pc; } private: inline TConnList& ConnList(size_t addrId) { return Lst_.Get(addrId); } inline size_t Validate(TConnList& cl) { size_t pc = 0; size_t nc = cl.Size(); TConn* conn; while (nc-- && cl.Dequeue(&conn)) { if (conn->IsValid()) { cl.Enqueue(conn); } else { ++pc; conn->SetCached(false); CachedConn_.Dec(); conn->UnRef(); } } return pc; } NNeh::NHttp::TLockFreeSequence Lst_; TAtomicCounter CachedConn_; }; } }