📄 filecache.cpp
字号:
{
MLOG_HTTP("CHXFileCacheObject::AddBlock()\n");
if(pBlock == NULL)
{
return HXR_INVALID_PARAMETER;
}
if(m_pList == NULL)
return HXR_UNEXPECTED;
if(m_pPendingAddBlock != NULL)
{
return HXR_UNEXPECTED;
}
else
{
m_pPendingAddBlock = pBlock;
m_pPendingAddBlock->AddRef();
}
if(!m_bInAddBlockDone)
{
while(m_pPendingAddBlock)
{
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)
{
pTempBlock->Release();
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_pCacheObjectResponse->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
CHXFileCacheObject::VerifyBlock(UINT32 /*IN*/ ulBlockOffset,
UINT32 /*IN*/ ulBlockLength)
{
MLOG_HTTP("CHXFileCacheObject::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_pCacheObjectResponse->VerifyBlockDone(bExists);
return HXR_OK;
} // VerifyBlock()
/************************************************************************
* Method:
*
* IHXCacheObject::ReadBlock
*
* Purpose:
*
* Read a block out of the cache.
*/
STDMETHODIMP
CHXFileCacheObject::ReadBlock(UINT32 /*IN*/ ulBlockOffset,
UINT32 /*IN*/ ulBlockLength)
{
MLOG_HTTP("CHXFileCacheObject::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) && (m_ulCurrentWriteOffset == 0) )
{
res2 = HXR_INCOMPLETE;
HX_RELEASE(pTempBlock);
pTempBlock = NULL;
}
else if(ulTempOffset < ulLeastOffset)
{
res2 = HXR_INCOMPLETE;
HX_RELEASE(pTempBlock);
pTempBlock = NULL;
// Flush data to file and then read the required (past)
// data from the file.
_CopyAllDataToFile();
UINT32 ulGap = ulLeastOffset - ulTempOffset;
UINT32 ulDiscardData = 0;
if(ulGap >= m_ulCapacity)
ulDiscardData = m_ulUsedCapacity;
else
{
int nRemovableData = m_ulCurrentWriteOffset -
(ulTempOffset + m_ulCapacity);
ulDiscardData = (nRemovableData > 0)? (UINT32)nRemovableData: 0;
}
if(ulDiscardData >0)
{
_DiscardDataFromTail(ulDiscardData, FALSE);
}
if(ulGap >= m_ulCapacity)
{
_CopyFromFileToHead(ulTempOffset, m_ulCapacity);
m_ulCurrentWriteOffset = ulTempOffset + m_ulCapacity;
m_ulCurrentReadOffset = ulTempOffset;
m_ulUsedCapacity = m_ulCapacity;
}
else
{
m_ulCurrentWriteOffset = ulTempOffset + ulGap + m_ulUsedCapacity;
//if(ulDiscardData != 0)
//{
_CopyFromFileToHead(ulTempOffset, ulGap);
//}
m_ulCurrentReadOffset = ulTempOffset;
}
}
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 = 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();
if(m_ulHighestByteNotRead < m_ulCurrentReadOffset)
m_ulHighestByteNotRead = m_ulCurrentReadOffset;
m_bInReadBlockDone = TRUE;
m_pCacheObjectResponse->ReadBlockDone(res2, pTempBlock);
m_bInReadBlockDone = FALSE;
HX_RELEASE(pTempBlock);
}
}
return HXR_OK;
} // ReadBlock()
/************************************************************************
* Method:
* IHXCacheObject::Flush
*
* Purpose:
*
* Flushes all data to the cache file AND releases all data buffers
* in the memory.After flushing, the object can be used for reading/writing
* as before.
*/
STDMETHODIMP
CHXFileCacheObject::Flush(void)
{
MLOG_HTTP("CHXFileCacheObject::Flush()\n");
if(!m_pList)
return HXR_UNEXPECTED;
m_pMutex->Lock();
_DiscardDataFromHead(m_ulUsedCapacity, TRUE);
m_ulUsedCapacity = 0;
m_pMutex->Unlock();
m_pCacheObjectResponse->FlushDone(HXR_OK);
return HXR_OK;
} // Flush()
/************************************************************************
* Method:
*
* IHXCacheObject::IsFull
*
* Purpose:
*
* Can the cache object accept any more data for storage?
*/
STDMETHODIMP_(BOOL)
CHXFileCacheObject::IsFull()
{
MLOG_HTTP("CHXFileCacheObject::IsFull()\n");
if(GetUnusedCapacity() == 0)
return TRUE;
else
return FALSE;
} // IsFull()
/************************************************************************
* Method:
*
* IHXCacheObject::IsEmpty
*
* Purpose:
*
* Does the cache object have any data stored?
*/
STDMETHODIMP_(BOOL)
CHXFileCacheObject::IsEmpty()
{
MLOG_HTTP("CHXFileCacheObject::IsEmpty()\n");
if(m_ulUsedCapacity == 0)
return TRUE;
else
return FALSE;
} // IsEmpty()
// Discards exactly 'byteCount' amount of data from the head.
// 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 CHXFileCacheObject::_DiscardDataFromHead(UINT32 byteCount, BOOL bWriteToFile)
{
MLOG_HTTP("CHXFileCacheObject::_DiscardDataFromHead(%u, %d)\n", byteCount, bWriteToFile);
HX_RESULT res = HXR_UNEXPECTED;
UINT32 ulDiscardedData = 0;
Info *headInfo = NULL;
LISTPOSITION currHead = m_pList->GetHeadPosition();
while(currHead != NULL)
{
headInfo = (Info*)m_pList->RemoveHead();
UINT32 ulHeadBlockOffset = headInfo->ulOffset;
UINT32 ulHeadBlockSize = headInfo->ulSize;
// This whole block should be discarded
if(ulDiscardedData + ulHeadBlockSize <= byteCount)
{
if(bWriteToFile == TRUE)
{
// If data already written to file, no need to write again.
if( (m_ulFileWriteOffset >= ulHeadBlockOffset) &&
(m_ulFileWriteOffset <= ulHeadBlockOffset + ulHeadBlockSize - 1) )
{
UINT32 ulDataAlreadyWritten = m_ulFileWriteOffset - ulHeadBlockOffset;
UINT32 ulDataToWrite = ulHeadBlockSize - ulDataAlreadyWritten;
fseek(m_pCacheFileHandle, m_ulFileWriteOffset, SEEK_SET);
int nBytesWritten = fwrite( (void*)(headInfo->pBlock->GetBuffer() + ulDataAlreadyWritten),
sizeof(UCHAR), ulDataToWrite, m_pCacheFileHandle);
fflush(m_pCacheFileHandle);
m_ulFileWriteOffset += ulDataToWrite;
}
}
headInfo->pBlock->Release();
delete headInfo;
ulDiscardedData += ulHeadBlockSize;
}
else // Only part of the block needs to be discarded.
{
if(ulDiscardedData + ulHeadBlockSize > byteCount) // >>> Redundant condition
{
UINT32 ulValidDataSize = (ulDiscardedData + ulHeadBlockSize - byteCount);
UINT32 ulInvalidDataSize = ulHeadBlockSize - ulValidDataSize;
if(bWriteToFile == TRUE)
{
// If data already written to file, no need to write again.
if( (m_ulFileWriteOffset >= ulHeadBlockOffset) &&
(m_ulFileWriteOffset <= ulHeadBlockOffset + ulInvalidDataSize - 1) )
{
UINT32 ulDataAlreadyWritten = m_ulFileWriteOffset - ulHeadBlockOffset;
UINT32 ulDataToWrite = ulInvalidDataSize - ulDataAlreadyWritten;
fseek(m_pCacheFileHandle, m_ulFileWriteOffset, SEEK_SET);
int nBytesWritten = fwrite( (void*)(headInfo->pBlock->GetBuffer() + ulDataAlreadyWritten),
sizeof(UCHAR), ulDataToWrite, m_pCacheFileHandle);
fflush(m_pCacheFileHandle);
m_ulFileWriteOffset += ulDataToWrite;
}
}
Info *pNewInfo = new Info;
if(pNewInfo == NULL)
{
res = HXR_OUTOFMEMORY;
break;
}
m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
(void **) &(pNewInfo->pBlock));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -