blob: 944ba4cfec227acd6459a92489574221d3c87ad8 (
plain) (
tree)
|
|
#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_;
};
}
}
|