Files
mir_server/sdk/commonLib/include/HandleMgr.h

537 lines
16 KiB
C
Raw Normal View History

2025-01-09 17:45:40 +08:00
/*
Handle类通常是只读的无符号整数
Handle是参数化的类TAG类型来完整定义
TAG除了区分句柄类型外不起任何作用,TAG类型的对象在系统任何地方都不会被用到
使Handle类型可以确保
Handle类型的参数TAG类型可以是任何形式的类型.
*/
#ifndef _DEBUG
#include <new>
//#include <time.h>
#endif
//#include <vector>
//#include <cassert>
//实现对象的重用,而且管理实体
//参见: http://hi.baidu.com/zyb_debug/blog/item/eaf6ea8ce55f291bb21bba4c.html
#pragma once
enum
{
// sizes to use for bit fields 使用位域(bit fields)的大小
MAX_BITS_INDEX = 21,
MAX_BITS_MAGIC = 11,
// sizes to compare against for asserting dereferences
MAX_INDEX = ( 1 << MAX_BITS_INDEX) - 1,
MAX_MAGIC = ( 1 << MAX_BITS_MAGIC) - 1,
//INVALID_INDEX =( 1 << MAX_BITS_INDEX), //非法的INDEX
};
//TAG在这里并没有什么用处,
template <typename TAG>
class Handle
{
union
{
struct
{
unsigned m_Index : MAX_BITS_INDEX; // index into resource array 资源数组的索引
unsigned m_Magic : MAX_BITS_MAGIC; // magic number to check 需要检查的魔术数
};
unsigned int m_Handle;
};
public:
// Lifetime.生命期
Handle( void ) : m_Handle( 0 ) { }
Handle( unsigned nHandle ) {m_Handle= nHandle ;} //
void Init( unsigned int index )
{
DbgAssert( IsNull() ); // don't allow reassignment 不允许重新赋值
DbgAssert( index <=MAX_INDEX ); // verify range 有限范围验证
//魔数初始化修改为一个随机数,避免出现一些特殊情况,增加服务器重启后可靠性
static unsigned int s_AutoMagic = rand();
IncMagicNumImpl(s_AutoMagic);
m_Index = index;
m_Magic = s_AutoMagic;
}
inline void updateMagic() {
unsigned int magic = m_Magic;
IncMagicNumImpl(magic);
m_Magic = magic;
}
// Query.查询
inline unsigned int GetIndex ( void ) const { return ( m_Index ); }
inline unsigned int GetMagic ( void ) const { return ( m_Magic ); }
inline unsigned int GetHandle( void ) const { return ( m_Handle ); }
bool IsNull ( void ) const { return ( !m_Handle ); }
inline unsigned GetMaxIndex(){return MAX_INDEX;}
operator unsigned int ( void ) const { return ( m_Handle ); }
protected:
inline void IncMagicNumImpl(unsigned int &magic)
{
if ( ++magic > MAX_MAGIC )
magic = 1; // 0 is used for "null handle"
}
};
template <typename DATA, typename HANDLE,int ONE_CHUNK_COUNT =1024>
class HandleMgr
{
public:
typedef DATA DataType;
typedef HANDLE HandleType;
//typedef HandleMgrStat Inherited;
HandleMgr(LPCTSTR lpszDesc);
~HandleMgr( )
{
Empty();
}
//申请一个数据指针
DATA* Acquire( HANDLE& handle );
//不使用指针,放到缓存池里去
void Release( HANDLE handle );
// 重新请求一个新句柄
bool ReNew( HANDLE &handle);
// 通过handle返回数据的指针
DATA* GetDataPtr( HANDLE handle );
const DATA* GetDataPtr( HANDLE handle ) const;
// other query 其他查询
inline unsigned int GetUsedHandleCount( void ) const
{
return ( m_nUsedCount );
}
inline UINT GetTotalHandleCount(void)
{
return (UINT)m_MagicNumbers.count() * ONE_CHUNK_COUNT;
}
inline int GetUserDataSize(void)
{
return m_nUsedCount * (sizeof(DATA) + ONE_CHUNK_COUNT);
}
inline bool HasUsedHandles( void ) const
{
return ( (GetTotalHandleCount() -GetUsedHandleCount()) >0 );
}
inline VOID GetChunkIdPos(UINT index, UINT &nChunkId, UINT & nPos)
{
nPos = index % ONE_CHUNK_COUNT; //取在chunk里的位置; //取在chunk里的位置
nChunkId = index / ONE_CHUNK_COUNT; //在第几个chunk
}
//通过数据指针释放
void ReleaseDataPtr( DATA * pData );
//获取第1个有效的数据指针结果的句柄要放在 hHandle,数据指针放在DATA*
DATA * First(HANDLE & hHandle);
DATA * Next(HANDLE & hHandle); //hHandle 句柄 下一个有效数据的指针DATA 为该数据指针
//清空内存
void Empty();
// 输出统计信息到文件
void dumpToFile()
{
}
private:
// private types
//
typedef wylib::container::CBaseList< wylib::container::CBaseList<DATA> > UserVec; //数据
typedef wylib::container::CBaseList< wylib::container::CBaseList<HANDLE> > MagicVec; //handle
typedef wylib::container::CBaseList< unsigned int> ChunkFreeCountVec; //每个块还有多少个空闲的句柄
UINT m_nFirstFreeIndex ; //第1个能用的index,这个用于指向释放了的第1个可用index
UINT m_nLastChunkFirstFreeIndex; //新申请的空闲列表的一个第1个可用的index
UINT m_nUsedCount; //
// private data
UserVec m_UserData; // 数据
MagicVec m_MagicNumbers; // 存的是每个数据当前使用的句柄
ChunkFreeCountVec m_FreeCounts; //每个块有多少个空闲的元素,这个保证每次查找可用的指针最多查找1024个对象
const static UINT INVALID_INDEX = ~0 ; //非法的指针
//const static int ONE_CHUNK_COUNT =1024 ; //每次申请1024个空间,这个要是2的n次幂
//const static int CHUNK_SHIFT_BIT_COUNT =10; //移位ONE_CHUNK_COUNT 需要移位运送多少位
//const static int CHUNK_MASK=0x3ff ; //取在1024块里的位置
};
template <typename TAG>
inline bool operator != ( Handle <TAG> l, Handle <TAG> r )
{
return ( l.GetHandle() != r.GetHandle() );
}
template <typename TAG>
inline bool operator == ( Handle <TAG> l, Handle <TAG> r )
{
return ( l.GetHandle() == r.GetHandle() );
}
template <typename DATA, typename HANDLE,int ONE_CHUNK_COUNT>
HandleMgr <DATA, HANDLE,ONE_CHUNK_COUNT> :: HandleMgr(LPCTSTR lpszDesc = NULL)
{
m_nFirstFreeIndex = INVALID_INDEX;
m_nLastChunkFirstFreeIndex = INVALID_INDEX;
m_nUsedCount =0;
}
template <typename DATA, typename HANDLE, int ONE_CHUNK_COUNT>
void HandleMgr <DATA, HANDLE,ONE_CHUNK_COUNT> ::Empty()
{
for(INT_PTR i=0; i<m_UserData.count(); i++)
{
for(INT_PTR j=0; j< ONE_CHUNK_COUNT ; j ++)
{
HANDLE hd = m_MagicNumbers[i][j];
if(! hd.IsNull() )
{
DATA *pdata =&( m_UserData[i][j]);
if(pdata)
{
pdata->~DATA();
}
TRACE(_T("Node not releaseed on HanderMgr destroy,DataSize =%d, hander=%d,index=%d\n"),sizeof(DATA),hd.GetHandle(),hd.GetIndex());
//OutputMsg(rmError,_T("Node not releaseed on HanderMgr destroy,DataSize =%d, hander=%d,index=%d"),sizeof(DATA),hd.GetHandle(),hd.GetIndex());
}
}
m_UserData[i].empty();
}
for(INT_PTR i=0; i<m_UserData.count(); i++)
{
m_MagicNumbers[i].empty();
}
m_UserData.empty();
m_MagicNumbers.empty();
}
template <typename DATA, typename HANDLE,int ONE_CHUNK_COUNT>
DATA* HandleMgr <DATA, HANDLE,ONE_CHUNK_COUNT> :: Acquire( HANDLE& handle )
{
// if free list is empty, add a new one otherwise use first one found 如果空闲列表为空,则新增一个,否则使用第一个可用表项
UINT index =INVALID_INDEX;
UINT nChunkId =0,nPos=0;
//如果前面有空闲的位置,优先使用空闲的对象
if (m_nFirstFreeIndex != INVALID_INDEX)
{
index = m_nFirstFreeIndex;
GetChunkIdPos(m_nFirstFreeIndex,nChunkId,nPos); // 获取当前空闲句柄的位置(在第几块的第几个槽)
m_nFirstFreeIndex = INVALID_INDEX; // 设置当前空闲有效句柄为INVALID_INDEX
//查找一个空闲的
for(INT i =nChunkId ; i < (INT)m_MagicNumbers.count(); i++) // m_MagicNumbers.count() 是数据块的数目
{
//只有在这个块有空闲的才去查找,避免了无效的查询,最多1024个
bool bFindNextFreeItem = false;
INT nFreeCount = m_FreeCounts[i];
if( nFreeCount > 0 )
{
INT j =0;
if( nChunkId == i ) //如果是本块,那么从后一个查起
{
j = nPos +1;
if(nFreeCount ==1) //本块只有1块,那肯定用过了阿
{
continue;
}
}
CBaseList<HANDLE> & pHandChunk = m_MagicNumbers[i]; // 第i块的句柄数据
for (; j < ONE_CHUNK_COUNT; j++)
{
//HANDLE hTemp = ;
if( pHandChunk[j].GetMagic() ==0)
{
m_nFirstFreeIndex = (i * ONE_CHUNK_COUNT) + j;// 下一个空闲句柄位置
bFindNextFreeItem = true;
break;
}
}
}
if (bFindNextFreeItem)
break;
}
//如果其已经到了空闲列表的最后一个了,那么说明前面已经没有可用使用的了
if (m_nFirstFreeIndex == m_nLastChunkFirstFreeIndex)
{
m_nFirstFreeIndex = INVALID_INDEX;
}
}
else
{
if(m_nLastChunkFirstFreeIndex == INVALID_INDEX ) //if no chunk
{
//已经无法申请了
UINT nTotalCount = GetTotalHandleCount();
Assert(nTotalCount == GetUsedHandleCount());
if ( (unsigned int) nTotalCount >= handle.GetMaxIndex()) return NULL; //已经无法申请了,超过了最大数量
CBaseList<DATA> dataChunk;
CBaseList<HANDLE> handleChunk;
m_UserData.addArray(&dataChunk,1); //添加到列表
m_MagicNumbers.addArray(&handleChunk,1);
INT_PTR nBackIndex = m_UserData.count(); // m_UserData.count() 是当前数据块的块数目
if (nBackIndex <1) return NULL;
nBackIndex --; // 最后一个块的索引
m_UserData[nBackIndex].reserve(ONE_CHUNK_COUNT); // 保证每个块都是同样长度
m_UserData[nBackIndex].trunc(ONE_CHUNK_COUNT);
m_MagicNumbers[nBackIndex].reserve(ONE_CHUNK_COUNT);
m_MagicNumbers[nBackIndex].trunc(ONE_CHUNK_COUNT);
HANDLE *pHandle = m_MagicNumbers[nBackIndex]; // 最后一个句柄块
memset(pHandle,0,sizeof(HANDLE) *ONE_CHUNK_COUNT ); // 初始化最后一个句柄块
//使用placement new 调用构造函数
m_nLastChunkFirstFreeIndex = nTotalCount; //当前的最大数量,指向下一个
m_FreeCounts.add(ONE_CHUNK_COUNT); //这个块还有多少个没有使用
//m_nAllocedChunkCount++;
}
if(m_nLastChunkFirstFreeIndex != INVALID_INDEX)
{
index = m_nLastChunkFirstFreeIndex;
m_nLastChunkFirstFreeIndex ++; //指向下一个
if(m_nLastChunkFirstFreeIndex >= (unsigned) GetTotalHandleCount()) //如果这个块使用完了,就需要重新申请空间了
{
m_nLastChunkFirstFreeIndex = INVALID_INDEX;
}
}
}
//实在是找不到可以使用的了
if ( index == INVALID_INDEX) return NULL;
handle.Init( index );
GetChunkIdPos(index,nChunkId,nPos);
unsigned int nFreeCount = m_FreeCounts[nChunkId];
if (nChunkId < (UINT)m_MagicNumbers.count() && nFreeCount >0 )
{
m_MagicNumbers[nChunkId][nPos] =handle;
}
else
{
return NULL;
}
m_FreeCounts[nChunkId]--; //这个列表空闲的数量
DATA *pData = &(m_UserData[nChunkId][nPos]);
new(pData)DATA();//placement new
m_nUsedCount++;
//m_nUsedHdlCount++;
//if (m_nUsedHdlCount > m_nMaxUsedHandleCount)
// m_nMaxUsedHandleCount = m_nUsedHdlCount;
return pData;
}
template <typename DATA, typename HANDLE,int ONE_CHUNK_COUNT>
void HandleMgr <DATA, HANDLE,ONE_CHUNK_COUNT> :: ReleaseDataPtr( DATA * pData )
{
UINT_PTR count =m_UserData.count();
SIZE_T nChunkSize = ONE_CHUNK_COUNT * sizeof(DATA); //每一块Chunk的大小,每次申请1024个
UINT_PTR nEndIndex = ONE_CHUNK_COUNT -1; //1023
for (UINT_PTR i= 0;i< count; i++)
{
DATA * pStart = &m_UserData[i][0];
DATA * pEnd = &m_UserData[i][nEndIndex];
INT_PTR nDataIndex = pData -pStart; //第多少个数据
if(nDataIndex >= 0 && pData <= pEnd) //找到了这个内存块
{
INT_PTR nByteDis = (char *)pData - (char *)pStart;
if( nByteDis % sizeof(DATA) != 0) //内存长度错误
{
return;
}
Release( m_MagicNumbers[i][nDataIndex] );
return;
}
}
}
template <typename DATA, typename HANDLE,int ONE_CHUNK_COUNT>
void HandleMgr <DATA, HANDLE,ONE_CHUNK_COUNT> :: Release( HANDLE handle )
{
// which one? 哪一个
if ( handle.IsNull() )return;
unsigned int index = handle.GetIndex();
UINT nChunkId =0,nPos=0;
GetChunkIdPos(index,nChunkId,nPos);
if( nChunkId >= (UINT)m_MagicNumbers.count() ) return ; //有问题,已经超过了
if (m_MagicNumbers[nChunkId][nPos].GetMagic() != handle.GetMagic()) return; //重复释放
// ok remove it - tag as unused and add to free list 可以删除了--表及其没有使用并加到空闲列表
if (index < m_nFirstFreeIndex )
{
m_nFirstFreeIndex = index;
}
HANDLE hTemp;
m_MagicNumbers[nChunkId][nPos] =hTemp;
//调用析构函数
DATA *pdata =&( m_UserData[nChunkId][nPos]);
if(pdata)
{
pdata->~DATA();
}
m_FreeCounts[nChunkId] ++; //这个块的空闲的个数 -1
m_nUsedCount--;
//m_nUsedHdlCount--;
}
template<typename DATA, typename HANDLE, int ONE_CHUNK_COUNT>
bool HandleMgr <DATA, HANDLE,ONE_CHUNK_COUNT> :: ReNew( HANDLE &handle)
{
if (handle.IsNull())
return false;
// check handle validity
unsigned int index = handle.GetIndex();
UINT nChunkId =0,nPos=0;
GetChunkIdPos(index,nChunkId,nPos);
if (nChunkId > (UINT)m_MagicNumbers.count() || m_MagicNumbers[nChunkId][nPos].GetMagic() != handle.GetMagic())
return false;
handle.updateMagic();
m_MagicNumbers[nChunkId][nPos] = handle;
return true;
}
template <typename DATA, typename HANDLE,int ONE_CHUNK_COUNT>
inline DATA* HandleMgr <DATA, HANDLE,ONE_CHUNK_COUNT>
:: GetDataPtr( HANDLE handle )
{
if ( handle.IsNull() ) return ( 0 );
unsigned int index = handle.GetIndex();
UINT nChunkId =0,nPos=0;
GetChunkIdPos(index,nChunkId,nPos);
// check handle validity - $ this check can be removed for speed 检查句柄有效性-为提供性能可以去掉这个检查
// if you can assume all handle references are always valid. 如果你假设索引句柄解引用都总是有效
if( nChunkId >=(UINT)m_MagicNumbers.count()) return NULL; //有问题,
if (m_MagicNumbers[nChunkId][nPos].GetMagic() != handle.GetMagic())
return NULL; //重复释放
return (& m_UserData[nChunkId][nPos] );
}
template <typename DATA, typename HANDLE,int ONE_CHUNK_COUNT>
inline const DATA* HandleMgr <DATA, HANDLE,ONE_CHUNK_COUNT>
:: GetDataPtr( HANDLE handle ) const
{
// this lazy cast is ok - non-const version does not modify anything
typedef HandleMgr <DATA, HANDLE> ThisType;
return ( const_cast <ThisType*> ( this )->GetDataPtr( handle ) );
}
//获取第1个有效的数据指针结果的句柄要放在 hHandle,数据指针放在DATA*
template <typename DATA, typename HANDLE,int ONE_CHUNK_COUNT>
DATA* HandleMgr <DATA, HANDLE,ONE_CHUNK_COUNT>
::First(HANDLE & hHandle)
{
INT_PTR count= m_FreeCounts.count();
for(int i=0; i< count; i++)
{
if(ONE_CHUNK_COUNT- m_FreeCounts[i] >0 ) //如果一个块里有数据,那么就在这个块里找
{
for(INT_PTR j=0; j< ONE_CHUNK_COUNT; j++)
{
if(m_MagicNumbers[i][j] != 0)
{
hHandle = m_MagicNumbers[i][j];
return &m_UserData[i][j];
}
}
}
}
return NULL;
}
//hHandle 句柄 下一个有效数据的指针DATA 为该数据指针
template <typename DATA, typename HANDLE,int ONE_CHUNK_COUNT>
DATA* HandleMgr <DATA, HANDLE,ONE_CHUNK_COUNT>
:: Next(HANDLE & hHandle)
{
if(hHandle ==0) return NULL; //压根就没有输入
UINT index = hHandle.GetIndex();
UINT nChunkId =0,nPos=0;
GetChunkIdPos(index,nChunkId,nPos);
for(INT_PTR i =nChunkId ; i < m_MagicNumbers.count(); i++)
{
//只有在这个块有空闲的才去查找,避免了无效的查询,最多1024个
INT_PTR nFreeCount = m_FreeCounts[i];
if( ONE_CHUNK_COUNT- nFreeCount >0 )
{
INT_PTR j =0;
if( nChunkId == i ) //如果是本块,那么从后一个查起
{
j = nPos +1;
if(nFreeCount ==1) //本块只有1块,那肯定用过了阿
{
continue;
}
}
CBaseList<HANDLE> & pHandChunk = m_MagicNumbers[i];
for (; j < ONE_CHUNK_COUNT; j++)
{
//HANDLE hTemp = ;
if( pHandChunk[j].GetMagic() !=0)
{
hHandle = pHandChunk[j];
return &m_UserData[i][j];
}
}
}
}
return NULL;
}