123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- #pragma once
- #include <string.h>
- #include <util/generic/ptr.h>
- #include <util/generic/singleton.h>
- #include <util/generic/string.h>
- #include <library/cpp/deprecated/atomic/atomic.h>
- #include <util/thread/lfqueue.h>
- #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 TConn>
- class TConnCache {
- struct TCounter : TAtomicCounter {
- inline void IncCount(const TConn* const&) {
- Inc();
- }
- inline void DecCount(const TConn* const&) {
- Dec();
- }
- };
- public:
- typedef TIntrusivePtr<TConn> TConnRef;
- class TConnList: public TLockFreeQueue<TConn*, TCounter> {
- 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<TConnList> Lst_;
- TAtomicCounter CachedConn_;
- };
- }
- }
|