📄 memcache.cpp
字号:
IHXBuffer* pTempBlock = m_pPendingAddBlock;
m_pPendingAddBlock = NULL;
UINT32 ulBlockSize = pTempBlock->GetSize();
Info *pNewInfo = NULL;
HX_RESULT res = HXR_OK;
if(ulBlockSize != 0)
{
m_pMutex->Lock();
// Can you accomodate this data?
if(m_ulUsedCapacity + ulBlockSize > m_ulCapacity)
{
res = HXR_OUTOFMEMORY;
}
else
{
pNewInfo = new Info;
if(pNewInfo == NULL)
res = HXR_OUTOFMEMORY;
}
if(HXR_OK == res)
{
// The new block should be contiguous
pNewInfo->ulOffset = m_ulCurrentWriteOffset;
pNewInfo->ulSize = ulBlockSize;
pNewInfo->pBlock = pTempBlock;
m_ulUsedCapacity += ulBlockSize;
m_ulCurrentWriteOffset += ulBlockSize;
m_pList->AddTail( (void *)pNewInfo );
}
m_pMutex->Unlock();
}
else
{
pTempBlock->Release();
}
m_bInAddBlockDone = TRUE;
m_pMemResponse->AddBlockDone(res);
m_bInAddBlockDone = FALSE;
} // while
}
return HXR_OK;
} // AddBlock()
/************************************************************************
* Method:
*
* IHXCacheObject::VerifyBlock
*
* Purpose:
*
* Verify that a block of data is in the cache.
*/
STDMETHODIMP
CHXMemCacheObject::VerifyBlock(UINT32 /*IN*/ ulBlockOffset,
UINT32 /*IN*/ ulBlockLength)
{
MLOG_HTTP("CHXMemCacheObject::VeifyBlock()\n");
if(m_pList == NULL)
return HXR_UNEXPECTED;
m_pMutex->Lock();
// Critical Section starts
BOOL bExists = TRUE;
if(m_ulUsedCapacity == 0)
{
bExists = FALSE;
}
else
{
UINT32 ulLeastOffset = m_ulCurrentWriteOffset - m_ulUsedCapacity;
UINT32 ulHighestOffset = m_ulCurrentWriteOffset - 1;
BOOL bStartExists = (ulBlockOffset >= ulLeastOffset) &&
(ulBlockOffset <= ulHighestOffset);
BOOL bEndExists = (ulBlockOffset + ulBlockLength - 1 >= ulLeastOffset) &&
(ulBlockOffset + ulBlockLength - 1 <= ulHighestOffset);
bExists = bStartExists && bEndExists;
}
// Critical section ends
m_pMutex->Unlock();
m_pMemResponse->VerifyBlockDone(bExists);
return HXR_OK;
} // VerifyBlock()
/************************************************************************
* Method:
*
* IHXCacheObject::ReadBlock
*
* Purpose:
*
* Read a block out of the cache.
*/
STDMETHODIMP
CHXMemCacheObject::ReadBlock(UINT32 /*IN*/ ulBlockOffset,
UINT32 /*IN*/ ulBlockLength)
{
MLOG_HTTP("CHXMemCacheObject::ReadBlock(Offset = %u, Length = %u)\n", ulBlockOffset, ulBlockLength);
if(m_pList == NULL)
return HXR_UNEXPECTED;
if(m_pPendingReadInfo.pBlock != NULL)
return HXR_UNEXPECTED;
m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
(void **) &m_pPendingReadInfo.pBlock);
if(m_pPendingReadInfo.pBlock == NULL)
return HXR_OUTOFMEMORY;
HX_RESULT res = m_pPendingReadInfo.pBlock->SetSize(ulBlockLength);
if(res != HXR_OK)
{
m_pPendingReadInfo.pBlock->Release();
m_pPendingReadInfo.pBlock = NULL;
return res;
}
m_pPendingReadInfo.ulLength = ulBlockLength;
m_pPendingReadInfo.ulOffset = ulBlockOffset;
if(!m_bInReadBlockDone)
{
while(m_pPendingReadInfo.pBlock)
{
HX_RESULT res2 = HXR_OK;
// To prepare for the possibilty of ReadBlock()
// being called from ReadBlockDone()
IHXBuffer* pTempBlock = m_pPendingReadInfo.pBlock;
m_pPendingReadInfo.pBlock = NULL;
UINT32 ulTempLength = m_pPendingReadInfo.ulLength;
m_pPendingReadInfo.ulLength = 0;
UINT32 ulTempOffset = m_pPendingReadInfo.ulOffset;
m_pPendingReadInfo.ulOffset = 0;
m_pMutex->Lock();
UINT32 ulLeastOffset = m_ulCurrentWriteOffset - m_ulUsedCapacity;
UINT32 ulHighestOffset = m_ulCurrentWriteOffset - 1;
if(m_ulUsedCapacity == 0)
{
if(ulTempOffset >= m_ulCurrentWriteOffset)
res2 = HXR_INCOMPLETE;
else
res2 = HXR_FAIL;
HX_RELEASE(pTempBlock);
pTempBlock = NULL;
}
else if(ulTempOffset < ulLeastOffset)
{
res2 = HXR_FAIL;
HX_RELEASE(pTempBlock);
pTempBlock = NULL;
}
else if(ulTempOffset > ulHighestOffset)
{
res2 = HXR_INCOMPLETE;
HX_RELEASE(pTempBlock);
pTempBlock = NULL;
// If 'forward data' requested, mark all data as read so
// that old data can be discarded to make space for new data.
//m_ulCurrentReadOffset = ulHighestOffset + 1;
m_ulCurrentReadOffset = ulTempOffset;
_CheckForThresholdCondition();
}
else
{
// Fill the pTempBlock with data from the list
UCHAR* ucTempBlockData = pTempBlock->GetBuffer();
UINT32 ulBytesReadFromList = 0;
LISTPOSITION currPos = m_pList->GetHeadPosition();
Info* currInfo;
while(currPos != NULL)
{
currInfo = (Info *)m_pList->GetNext(currPos);
UINT32 ulCurrLowOffset = currInfo->ulOffset;
UINT32 ulCurrHighOffset = currInfo->ulOffset + currInfo->ulSize - 1;
UCHAR* ucCurrBlockData = currInfo->pBlock->GetBuffer();
if( (ulTempOffset >= ulCurrLowOffset) && (ulTempOffset <= ulCurrHighOffset) )
{
UINT32 ulMatchSize = ( (ulCurrHighOffset - ulTempOffset + 1) < ulTempLength ) ?
ulCurrHighOffset - ulTempOffset + 1 : ulTempLength;
memcpy((void*)(ucTempBlockData + ulBytesReadFromList),
(void*)(ucCurrBlockData + ulTempOffset - ulCurrLowOffset), ulMatchSize);
ulBytesReadFromList += ulMatchSize;
ulTempOffset += ulMatchSize;
ulTempLength -= ulMatchSize;
if(0 == ulTempLength)
break;
}
}
if(ulTempLength > 0)
{
res2 = HXR_INCOMPLETE;
pTempBlock->SetSize(ulBytesReadFromList);
}
else
{
res2 = HXR_OK;
}
m_ulCurrentReadOffset = ulTempOffset;
_CheckForThresholdCondition();
}
m_pMutex->Unlock();
m_bInReadBlockDone = TRUE;
m_pMemResponse->ReadBlockDone(res2, pTempBlock);
m_bInReadBlockDone = FALSE;
HX_RELEASE(pTempBlock);
}
}
return HXR_OK;
} // ReadBlock()
/************************************************************************
* Method:
* IHXCacheObject::Flush
*
* Purpose:
*
* Releases all data buffers cached in the object. The object now
* gets to a same state as when it was newly created. After flushine,
* the object can be used for reading/writing as before.
*/
STDMETHODIMP
CHXMemCacheObject::Flush(void)
{
MLOG_HTTP("CHXMemCacheObject::Flush()\n");
if(!m_pList)
return HXR_UNEXPECTED;;
m_pMutex->Lock();
LISTPOSITION currPos = m_pList->GetHeadPosition();
Info* currInfo;
while(currPos != NULL)
{
currInfo = (Info *)m_pList->GetNext(currPos);
currInfo->pBlock->Release();
delete currInfo;
}
m_pList->RemoveAll();
m_ulUsedCapacity = 0;
m_ulCurrentWriteOffset = 0;
m_ulCurrentReadOffset = 0;
m_pMutex->Unlock();
m_pMemResponse->FlushDone(HXR_OK);
return HXR_OK;
} // Flush()
/************************************************************************
* Method:
*
* IHXCacheObject::IsFull
*
* Purpose:
*
* Can the cache object accept any more data for storage?
*/
STDMETHODIMP_(BOOL)
CHXMemCacheObject::IsFull()
{
MLOG_HTTP("CHXMemCacheObject::IsFull()\n");
m_pMutex->Lock();
BOOL bIsFull = TRUE;
if(m_ulUsedCapacity < m_ulCapacity)
bIsFull = FALSE;
m_pMutex->Unlock();
return bIsFull;
} // IsFull()
/************************************************************************
* Method:
*
* IHXCacheObject::IsEmpty
*
* Purpose:
*
* Does the cache object have any data stored?
*/
STDMETHODIMP_(BOOL)
CHXMemCacheObject::IsEmpty()
{
MLOG_HTTP("CHXMemCacheObject::IsEmpty()\n");
if(m_ulUsedCapacity == 0)
return TRUE;
else
return FALSE;
} // IsEmpty()
// Discards exactly 'byteCount' amount of oldest data.
// Note that this method is not thread safe. The caller has to take
// care of locking common data structures before calling this method.
HX_RESULT CHXMemCacheObject::_DiscardData(UINT32 byteCount)
{
MLOG_HTTP("CHXMemCacheObject::_DiscardData(%u)\n", byteCount);
HX_RESULT res = HXR_UNEXPECTED;
UINT32 ulDiscardedData = 0;
LISTPOSITION currHeadPos = NULL;
Info *headInfo = NULL;
while( (currHeadPos = m_pList->GetHeadPosition())!= NULL )
{
headInfo = (Info*)(m_pList->RemoveHead());
UINT32 ulHeadBlockSize = headInfo->ulSize;
if(ulDiscardedData + ulHeadBlockSize <= byteCount)
{
headInfo->pBlock->Release();
delete headInfo;
ulDiscardedData += ulHeadBlockSize;
}
else
{
if(ulDiscardedData + ulHeadBlockSize > byteCount)
{
UINT32 ulValidDataSize = (ulDiscardedData + ulHeadBlockSize - byteCount);
UINT32 ulInvalidDataSize = ulHeadBlockSize - ulValidDataSize;
Info *pNewInfo = new Info;
if(pNewInfo == NULL)
{
res = HXR_OUTOFMEMORY;
break;
}
m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
(void **) &(pNewInfo->pBlock));
if(pNewInfo->pBlock == NULL)
break;
res = pNewInfo->pBlock->SetSize(ulValidDataSize);
if(res != HXR_OK)
break;
memcpy( (void*)(pNewInfo->pBlock->GetBuffer()),
(void*)(headInfo->pBlock->GetBuffer()+ ulInvalidDataSize),
ulValidDataSize );
pNewInfo->ulOffset = headInfo->ulOffset + ulInvalidDataSize;
pNewInfo->ulSize = ulValidDataSize;
m_pList->AddHead( (void *)pNewInfo );
headInfo->pBlock->Release();
delete headInfo;
}
ulDiscardedData = byteCount;
headInfo = NULL;
res = HXR_OK;
break;
}
}
m_ulUsedCapacity -= ulDiscardedData;
return res;
}
// Check if utilizedData has exceeded THRESHOLD. If yes, discard
// appropriate amount of data. Note that this
// method is not thread safe. The caller has to take care of
// locking common data structures before calling this method.
HX_RESULT CHXMemCacheObject::_CheckForThresholdCondition()
{
MLOG_HTTP("CHXMemCacheObject::_CheckForThresholdCondition()\n");
if(m_ulUsedCapacity == 0)
{
return HXR_OK;
}
UINT32 ulLeastOffset = m_ulCurrentWriteOffset - m_ulUsedCapacity;
UINT32 ulHighestOffset = m_ulCurrentWriteOffset - 1;
HX_RESULT res = HXR_OK;
INT32 ulExcess = (m_ulCurrentReadOffset - ulLeastOffset) -
(INT32)(m_lThreshold * m_ulCapacity * 0.01);
if(ulExcess > 0)
{
if(ulExcess > m_ulUsedCapacity)
ulExcess = m_ulUsedCapacity;
res = _DiscardData(ulExcess);
}
return res;
} // _CheckForThresholdCondition()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -