Files
hpsocket-linux/common/BufferPool.h
2025-04-17 20:38:35 +08:00

870 lines
17 KiB
C++

/*
* Copyright: JessMA Open Source (ldcsaa@gmail.com)
*
* Author : Bruce Liang
* Website : https://github.com/ldcsaa
* Project : https://github.com/ldcsaa/HP-Socket
* Blog : http://www.cnblogs.com/ldcsaa
* Wiki : http://www.oschina.net/p/hp-socket
* QQ Group : 44636872, 75375912
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "hpsocket/GlobalDef.h"
#include "Singleton.h"
#include "STLHelper.h"
#include "RingBuffer.h"
#include "PrivateHeap.h"
#include "CriSec.h"
template<class T> T* ConstructItemT(T*, CPrivateHeap& heap, int capacity, BYTE* pData, int length)
{
ASSERT(capacity > 0);
int item_size = sizeof(T);
T* pItem = (T*)heap.Alloc(item_size + capacity);
BYTE* pHead = (BYTE*)pItem + item_size;
return ::ConstructObject(pItem, heap, pHead, capacity, pData, length);
}
template<class T> void DestructItemT(T* pItem)
{
ASSERT(pItem != nullptr);
CPrivateHeap& heap = pItem->GetPrivateHeap();
::DestructObject(pItem);
heap.Free(pItem);
}
struct TItem
{
template<typename T> friend struct TSimpleList;
template<typename T> friend class CNodePoolT;
template<typename T> friend struct TItemListT;
friend struct TBuffer;
public:
int Cat (const BYTE* pData, int length);
int Cat (const TItem& other);
int Fetch (BYTE* pData, int length);
int Peek (BYTE* pData, int length);
int Increase(int length);
int Reduce (int length);
void Reset (int first = 0, int last = 0);
BYTE* Ptr () {return begin;}
const BYTE* Ptr () const {return begin;}
int Size () const {return (int)(end - begin);}
int Remain () const {return capacity - (int)(end - head);}
int Capacity() const {return capacity;}
bool IsEmpty () const {return Size() == 0;}
bool IsFull () const {return Remain() == 0;}
CPrivateHeap& GetPrivateHeap() {return heap;}
operator BYTE* () {return Ptr();}
operator const BYTE* () const {return Ptr();}
public:
static TItem* Construct(CPrivateHeap& heap,
int capacity = DEFAULT_ITEM_CAPACITY,
BYTE* pData = nullptr,
int length = 0)
{
return ::ConstructItemT((TItem*)(nullptr), heap, capacity, pData, length);
}
static void Destruct(TItem* pItem)
{
::DestructItemT(pItem);
}
TItem(CPrivateHeap& hp, BYTE* pHead, int cap = DEFAULT_ITEM_CAPACITY, BYTE* pData = nullptr, int length = 0)
: heap(hp), head(pHead), begin(pHead), end(pHead), capacity(cap), next(nullptr), last(nullptr)
{
if(pData != nullptr && length != 0)
Cat(pData, length);
}
~TItem() {}
DECLARE_NO_COPY_CLASS(TItem)
public:
static const DWORD DEFAULT_ITEM_CAPACITY;
private:
CPrivateHeap& heap;
private:
TItem* next;
TItem* last;
int capacity;
BYTE* head;
BYTE* begin;
BYTE* end;
};
template<class T> struct TSimpleList
{
public:
T* PushFront(T* pItem)
{
if(pFront != nullptr)
{
pFront->last = pItem;
pItem->next = pFront;
}
else
{
pItem->last = nullptr;
pItem->next = nullptr;
pBack = pItem;
}
pFront = pItem;
++size;
return pItem;
}
T* PushBack(T* pItem)
{
if(pBack != nullptr)
{
pBack->next = pItem;
pItem->last = pBack;
}
else
{
pItem->last = nullptr;
pItem->next = nullptr;
pFront = pItem;
}
pBack = pItem;
++size;
return pItem;
}
T* PopFront()
{
T* pItem = pFront;
if(pFront != pBack)
{
pFront = (T*)pFront->next;
pFront->last = nullptr;
}
else if(pFront != nullptr)
{
pFront = nullptr;
pBack = nullptr;
}
if(pItem != nullptr)
{
pItem->next = nullptr;
pItem->last = nullptr;
--size;
}
return pItem;
}
T* PopBack()
{
T* pItem = pBack;
if(pFront != pBack)
{
pBack = (T*)pBack->last;
pBack->next = nullptr;
}
else if(pBack != nullptr)
{
pFront = nullptr;
pBack = nullptr;
}
if(pItem != nullptr)
{
pItem->next = nullptr;
pItem->last = nullptr;
--size;
}
return pItem;
}
TSimpleList<T>& Shift(TSimpleList<T>& other)
{
if(&other != this && other.size > 0)
{
if(size > 0)
{
pBack->next = other.pFront;
other.pFront->last = pBack;
}
else
{
pFront = other.pFront;
}
pBack = other.pBack;
size += other.size;
other.Reset();
}
return *this;
}
void Clear()
{
if(size > 0)
{
T* pItem;
while((pItem = PopFront()) != nullptr)
T::Destruct(pItem);
}
}
T* Front () const {return pFront;}
T* Back () const {return pBack;}
int Size () const {return size;}
bool IsEmpty () const {return size == 0;}
public:
TSimpleList() {Reset();}
~TSimpleList() {Clear();}
DECLARE_NO_COPY_CLASS(TSimpleList<T>)
private:
void Reset()
{
pFront = nullptr;
pBack = nullptr;
size = 0;
}
private:
int size;
T* pFront;
T* pBack;
};
template<class T> class CNodePoolT
{
public:
void PutFreeItem(T* pItem)
{
ASSERT(pItem != nullptr);
if(!m_lsFreeItem.TryPut(pItem))
T::Destruct(pItem);
}
void PutFreeItem(TSimpleList<T>& lsItem)
{
if(lsItem.IsEmpty())
return;
T* pItem;
while((pItem = lsItem.PopFront()) != nullptr)
PutFreeItem(pItem);
}
T* PickFreeItem()
{
T* pItem = nullptr;
if(!m_lsFreeItem.TryGet(&pItem))
pItem = T::Construct(m_heap, m_dwItemCapacity);
ASSERT(pItem);
pItem->Reset();
return pItem;
}
void Prepare()
{
m_lsFreeItem.Reset(m_dwPoolSize);
}
void Clear()
{
m_lsFreeItem.Clear();
m_heap.Reset();
}
public:
void SetItemCapacity(DWORD dwItemCapacity) {m_dwItemCapacity = dwItemCapacity;}
void SetPoolSize (DWORD dwPoolSize) {m_dwPoolSize = dwPoolSize;}
void SetPoolHold (DWORD dwPoolHold) {m_dwPoolHold = dwPoolHold;}
DWORD GetItemCapacity () {return m_dwItemCapacity;}
DWORD GetPoolSize () {return m_dwPoolSize;}
DWORD GetPoolHold () {return m_dwPoolHold;}
CPrivateHeap& GetPrivateHeap() {return m_heap;}
public:
CNodePoolT( DWORD dwPoolSize = DEFAULT_POOL_SIZE,
DWORD dwPoolHold = DEFAULT_POOL_HOLD,
DWORD dwItemCapacity = DEFAULT_ITEM_CAPACITY)
: m_dwPoolSize(dwPoolSize)
, m_dwPoolHold(dwPoolHold)
, m_dwItemCapacity(dwItemCapacity)
{
}
~CNodePoolT() {Clear();}
DECLARE_NO_COPY_CLASS(CNodePoolT)
public:
static const DWORD DEFAULT_ITEM_CAPACITY;
static const DWORD DEFAULT_POOL_SIZE;
static const DWORD DEFAULT_POOL_HOLD;
private:
CPrivateHeap m_heap;
DWORD m_dwItemCapacity;
DWORD m_dwPoolSize;
DWORD m_dwPoolHold;
CRingPool<T> m_lsFreeItem;
};
template<class T> const DWORD CNodePoolT<T>::DEFAULT_ITEM_CAPACITY = TItem::DEFAULT_ITEM_CAPACITY;
template<class T> const DWORD CNodePoolT<T>::DEFAULT_POOL_SIZE = DEFAULT_BUFFER_CACHE_POOL_SIZE;
template<class T> const DWORD CNodePoolT<T>::DEFAULT_POOL_HOLD = DEFAULT_BUFFER_CACHE_POOL_HOLD;
using CItemPool = CNodePoolT<TItem>;
template<class T> struct TItemListT : public TSimpleList<T>
{
using __super = TSimpleList<T>;
public:
int PushTail(const BYTE* pData, int length)
{
ASSERT(length <= (int)itPool.GetItemCapacity());
if(length > (int)itPool.GetItemCapacity())
return 0;
T* pItem = __super::PushBack(itPool.PickFreeItem());
return pItem->Cat(pData, length);
}
int Cat(const BYTE* pData, int length)
{
int remain = length;
while(remain > 0)
{
T* pItem = __super::Back();
if(pItem == nullptr || pItem->IsFull())
pItem = __super::PushBack(itPool.PickFreeItem());
int cat = pItem->Cat(pData, remain);
pData += cat;
remain -= cat;
}
return length;
}
int Cat(const T* pItem)
{
return Cat(pItem->Ptr(), pItem->Size());
}
int Cat(const TItemListT<T>& other)
{
ASSERT(this != &other);
int length = 0;
for(T* pItem = other.Front(); pItem != nullptr; pItem = pItem->next)
length += Cat(pItem);
return length;
}
int Fetch(BYTE* pData, int length)
{
int remain = length;
while(remain > 0 && __super::Size() > 0)
{
T* pItem = __super::Front();
int fetch = pItem->Fetch(pData, remain);
pData += fetch;
remain -= fetch;
if(pItem->IsEmpty())
itPool.PutFreeItem(__super::PopFront());
}
return length - remain;
}
int Peek(BYTE* pData, int length)
{
int remain = length;
T* pItem = __super::Front();
while(remain > 0 && pItem != nullptr)
{
int peek = pItem->Peek(pData, remain);
pData += peek;
remain -= peek;
pItem = pItem->next;
}
return length - remain;
}
int Increase(int length)
{
int remain = length;
while(remain > 0)
{
T* pItem = __super::Back();
if(pItem == nullptr || pItem->IsFull())
{
pItem = itPool.PickFreeItem();
__super::PushBack(pItem);
}
remain -= pItem->Increase(remain);
}
return length - remain;
}
int Reduce(int length)
{
int remain = length;
while(remain > 0 && __super::Size() > 0)
{
T* pItem = __super::Front();
remain -= pItem->Reduce(remain);
if(pItem->IsEmpty())
itPool.PutFreeItem(__super::PopFront());
}
return length - remain;
}
void Release()
{
itPool.PutFreeItem(*this);
}
CNodePoolT<T>& GetItemPool() {return itPool;}
public:
TItemListT(CNodePoolT<T>& pool) : itPool(pool)
{
}
private:
CNodePoolT<T>& itPool;
};
using TItemList = TItemListT<TItem>;
template<class T, class length_t = int, typename = enable_if_t<is_integral<typename decay<length_t>::type>::value>>
struct TItemListExT : public TItemListT<T>
{
using __super = TItemListT<T>;
public:
T* PushFront(T* pItem)
{
length += pItem->Size();
return __super::PushFront(pItem);
}
T* PushBack(T* pItem)
{
length += pItem->Size();
return __super::PushBack(pItem);
}
T* PopFront()
{
T* pItem = __super::PopFront();
if(pItem != nullptr)
length -= pItem->Size();
return pItem;
}
T* PopBack()
{
T* pItem = __super::PopBack();
if(pItem != nullptr)
length -= pItem->Size();
return pItem;
}
TItemListExT& Shift(TItemListExT<T>& other)
{
if(&other != this && other.length > 0)
{
length += other.length;
other.length = 0;
__super::Shift(other);
}
return *this;
}
void Clear()
{
__super::Clear();
length = 0;
}
void Release()
{
__super::Release();
length = 0;
}
public:
int PushTail(const BYTE* pData, int length)
{
int cat = __super::PushTail(pData, length);
this->length += cat;
return cat;
}
int Cat(const BYTE* pData, int length)
{
int cat = __super::Cat(pData, length);
this->length += cat;
return cat;
}
int Cat(const T* pItem)
{
int cat = __super::Cat(pItem->Ptr(), pItem->Size());
this->length += cat;
return cat;
}
int Cat(const TItemListT<T>& other)
{
int cat = __super::Cat(other);
this->length += cat;
return cat;
}
int Fetch(BYTE* pData, int length)
{
int fetch = __super::Fetch(pData, length);
this->length -= fetch;
return fetch;
}
int Increase(int length)
{
int increase = __super::Increase(length);
this->length += increase;
return increase;
}
int Reduce(int length)
{
int reduce = __super::Reduce(length);
this->length -= reduce;
return reduce;
}
typename decay<length_t>::type Length() const {return length;}
int IncreaseLength (int length) {return (this->length += length);}
int ReduceLength (int length) {return (this->length -= length);}
public:
TItemListExT(CNodePoolT<T>& pool) : TItemListT<T>(pool), length(0)
{
}
~TItemListExT()
{
ASSERT(length >= 0);
}
DECLARE_NO_COPY_CLASS(TItemListExT)
private:
length_t length;
};
using TItemListEx = TItemListExT<TItem>;
using TItemListExV = TItemListExT<TItem, volatile int>;
template<class T> struct TItemPtrT
{
public:
T* Reset(T* pItem = nullptr)
{
if(m_pItem != nullptr)
itPool.PutFreeItem(m_pItem);
m_pItem = pItem;
return m_pItem;
}
T* Attach(T* pItem)
{
return Reset(pItem);
}
T* Detach()
{
T* pItem = m_pItem;
m_pItem = nullptr;
return pItem;
}
T* New()
{
return Attach(itPool.PickFreeItem());
}
bool IsValid () {return m_pItem != nullptr;}
T* operator -> () {return m_pItem;}
T* operator = (T* pItem) {return Reset(pItem);}
operator T* () {return m_pItem;}
T*& PtrRef () {return m_pItem;}
T* Ptr () {return m_pItem;}
const T* Ptr () const {return m_pItem;}
operator const T* () const {return m_pItem;}
public:
TItemPtrT(CNodePoolT<T>& pool, T* pItem = nullptr)
: itPool(pool), m_pItem(pItem)
{
}
TItemPtrT(TItemListT<T>& ls, T* pItem = nullptr)
: itPool(ls.GetItemPool()), m_pItem(pItem)
{
}
~TItemPtrT()
{
Reset();
}
DECLARE_NO_COPY_CLASS(TItemPtrT)
private:
CNodePoolT<T>& itPool;
T* m_pItem;
};
using TItemPtr = TItemPtrT<TItem>;
class CBufferPool;
struct TBuffer
{
template<typename T> friend struct TSimpleList;
friend class CBufferPool;
public:
static TBuffer* Construct(CBufferPool& pool, ULONG_PTR dwID);
static void Destruct(TBuffer* pBuffer);
public:
int Cat (const BYTE* pData, int len);
int Cat (const TItem* pItem);
int Cat (const TItemList& other);
int Fetch (BYTE* pData, int length);
int Peek (BYTE* pData, int length);
int Reduce (int len);
public:
CCriSec& CriSec () {return cs;}
TItemList& ItemList() {return items;}
ULONG_PTR ID () const {return id;}
int Length () const {return length;}
bool IsValid () const {return id != 0;}
DWORD GetFreeTime () const {return freeTime;}
int GetCount () const {return 0;}
private:
int IncreaseLength (int len) {return (length += len);}
int DecreaseLength (int len) {return (length -= len);}
void Reset ();
private:
friend TBuffer* ConstructObject<>(TBuffer*, CPrivateHeap&, CItemPool&, ULONG_PTR&);
friend void DestructObject<>(TBuffer*);
TBuffer(CPrivateHeap& hp, CItemPool& itPool, ULONG_PTR dwID = 0)
: heap(hp), items(itPool), id(dwID), length(0)
{
}
~TBuffer() {}
DECLARE_NO_COPY_CLASS(TBuffer)
private:
CPrivateHeap& heap;
private:
ULONG_PTR id;
int length;
DWORD freeTime;
private:
TBuffer* next;
TBuffer* last;
CCriSec cs;
TItemList items;
};
class CBufferPool
{
using TBufferList = CRingPool<TBuffer>;
using TBufferQueue = CCASQueue<TBuffer>;
using TBufferCache = CRingCache<TBuffer, ULONG_PTR, true>;
public:
void PutFreeBuffer (ULONG_PTR dwID);
TBuffer* PutCacheBuffer (ULONG_PTR dwID);
TBuffer* FindCacheBuffer (ULONG_PTR dwID);
TBuffer* PickFreeBuffer (ULONG_PTR dwID);
void PutFreeBuffer (TBuffer* pBuffer);
void Prepare ();
void Clear ();
void ReleaseGCBuffer (BOOL bForce = FALSE);
public:
void SetItemCapacity (DWORD dwItemCapacity) {m_itPool.SetItemCapacity(dwItemCapacity);}
void SetItemPoolSize (DWORD dwItemPoolSize) {m_itPool.SetPoolSize(dwItemPoolSize);}
void SetItemPoolHold (DWORD dwItemPoolHold) {m_itPool.SetPoolHold(dwItemPoolHold);}
void SetMaxCacheSize (DWORD dwMaxCacheSize) {m_dwMaxCacheSize = dwMaxCacheSize;}
void SetBufferLockTime (DWORD dwBufferLockTime) {m_dwBufferLockTime = dwBufferLockTime;}
void SetBufferPoolSize (DWORD dwBufferPoolSize) {m_dwBufferPoolSize = dwBufferPoolSize;}
void SetBufferPoolHold (DWORD dwBufferPoolHold) {m_dwBufferPoolHold = dwBufferPoolHold;}
DWORD GetItemCapacity () {return m_itPool.GetItemCapacity();}
DWORD GetItemPoolSize () {return m_itPool.GetPoolSize();}
DWORD GetItemPoolHold () {return m_itPool.GetPoolHold();}
DWORD GetMaxCacheSize () {return m_dwMaxCacheSize;}
DWORD GetBufferLockTime () {return m_dwBufferLockTime;}
DWORD GetBufferPoolSize () {return m_dwBufferPoolSize;}
DWORD GetBufferPoolHold () {return m_dwBufferPoolHold;}
TBuffer* operator [] (ULONG_PTR dwID) {return FindCacheBuffer(dwID);}
public:
CBufferPool(DWORD dwPoolSize = DEFAULT_BUFFER_POOL_SIZE,
DWORD dwPoolHold = DEFAULT_BUFFER_POOL_HOLD,
DWORD dwLockTime = DEFAULT_BUFFER_LOCK_TIME,
DWORD dwMaxCacheSize = DEFAULT_MAX_CACHE_SIZE)
: m_dwBufferPoolSize(dwPoolSize)
, m_dwBufferPoolHold(dwPoolHold)
, m_dwBufferLockTime(dwLockTime)
, m_dwMaxCacheSize(dwMaxCacheSize)
{
}
~CBufferPool() {Clear();}
DECLARE_NO_COPY_CLASS(CBufferPool)
public:
CPrivateHeap& GetPrivateHeap() {return m_heap;}
CItemPool& GetItemPool() {return m_itPool;}
public:
static const DWORD DEFAULT_MAX_CACHE_SIZE;
static const DWORD DEFAULT_ITEM_CAPACITY;
static const DWORD DEFAULT_ITEM_POOL_SIZE;
static const DWORD DEFAULT_ITEM_POOL_HOLD;
static const DWORD DEFAULT_BUFFER_LOCK_TIME;
static const DWORD DEFAULT_BUFFER_POOL_SIZE;
static const DWORD DEFAULT_BUFFER_POOL_HOLD;
private:
DWORD m_dwMaxCacheSize;
DWORD m_dwBufferLockTime;
DWORD m_dwBufferPoolSize;
DWORD m_dwBufferPoolHold;
CPrivateHeap m_heap;
CItemPool m_itPool;
TBufferCache m_bfCache;
TBufferList m_lsFreeBuffer;
TBufferQueue m_lsGCBuffer;
};