filecache.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:43k
- /* ***** BEGIN LICENSE BLOCK *****
- * Version: RCSL 1.0/RPSL 1.0
- *
- * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file, are
- * subject to the current version of the RealNetworks Public Source License
- * Version 1.0 (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the RealNetworks Community Source License Version 1.0
- * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl,
- * in which case the RCSL will apply. You may also obtain the license terms
- * directly from RealNetworks. You may not use this file except in
- * compliance with the RPSL or, if you have a valid RCSL with RealNetworks
- * applicable to this file, the RCSL. Please see the applicable RPSL or
- * RCSL for the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the portions
- * it created.
- *
- * This file, and the files included with this file, is distributed and made
- * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- #include "hxtypes.h"
- #include "hxcom.h" // IUnknown
- #include "hxiids.h" // GUIDs
- #include "hxslist.h" // CHXSimpleList
- #include "hxthread.h" // HXMutex
- #include "hxstring.h" // memcpy()
- #include "hxcomm.h" // IHXCommonClassFactory
- #include "ihxpckts.h" // IHXBuffer
- #include "hxcache2.h" // IHXCache2, IHXCacheObject, IHXCacheObjectResponse
- #include "filecache.h"
- #include "multilog.h"
- #include "mlog_http.h" // MLOG_HTTP()
- /****************************************************************************
- * CHXFileCacheObject::CHXFileCacheObject
- *
- * Constructor
- */
- CHXFileCacheObject::CHXFileCacheObject(IHXCommonClassFactory* /*IN*/ pClassFactory,
- UINT32 /*IN*/ ulFileLength,
- char* /*IN*/ pFileName)
- : m_RefCount (0),
- m_pCacheObjectResponse (NULL),
- m_pClassFactory (NULL),
- m_ulCapacity (0),
- m_lThreshold (50),
- m_ulUsedCapacity (0),
- m_pList (NULL),
- m_ulCurrentWriteOffset (0),
- m_pPendingAddBlock (NULL),
- m_bInAddBlockDone (FALSE),
- m_bInReadBlockDone (FALSE),
- m_pMutex (NULL),
- m_ulCurrentReadOffset (0),
- m_ulFileLength (0),
- m_pFileName (NULL),
- m_ulFileWriteOffset (0),
- m_pCacheFileHandle (NULL),
- m_ulHighestByteNotRead (0)
- {
- MLOG_HTTP("CHXFileCacheObject::CHXFileCacheObject(FileLen = %u, FileName = %s)n", ulFileLength, pFileName);
- m_pPendingReadInfo.ulOffset = 0;
- m_pPendingReadInfo.ulLength = 0;
- m_pPendingReadInfo.pBlock = NULL;
- if(pClassFactory != NULL)
- {
- m_pClassFactory = pClassFactory;
- m_pClassFactory->AddRef();
- }
- m_ulFileLength = ulFileLength;
- m_pFileName = pFileName;
- m_pList = new CHXSimpleList;
- #if defined(THREADS_SUPPORTED) || defined(_UNIX_THREADS_SUPPORTED)
- HXMutex::MakeMutex(m_pMutex);
- #else
- HXMutex::MakeStubMutex(m_pMutex);
- #endif
- }
- /****************************************************************************
- * CHXFileCacheObject::~CHXFileCacheObject
- *
- * Destructor
- */
- CHXFileCacheObject::~CHXFileCacheObject()
- {
- MLOG_HTTP("CHXFileCacheObject::~CHXFileCacheObject()n");
- m_pMutex->Lock();
- // Close the cache file and delete if necessary
- if(m_pCacheFileHandle != NULL)
- {
- // If full media clip not played, delete cache file
- if(m_ulHighestByteNotRead != m_ulFileLength)
- {
- fclose(m_pCacheFileHandle);
- remove(m_pFileName);
- }
- else
- {
- _CopyAllDataToFile();
- fclose(m_pCacheFileHandle);
- }
- }
- // Destroy the list
- if(m_pList)
- {
- LISTPOSITION currPos = m_pList->GetHeadPosition();
- Info* currInfo;
- while(currPos != NULL)
- {
- currInfo = (Info *)m_pList->GetNext(currPos);
- currInfo->pBlock->Release();
- delete currInfo;
- }
- delete m_pList;
- }
- m_pMutex->Unlock();
- HX_DELETE(m_pMutex);
- } // ~CHXFileCacheObject()
- // IUnknown COM Interface Methods
- /****************************************************************************
- * IUnknown::AddRef
- *
- * This routine increases the object reference count in a thread safe
- * manner. The reference count is used to manage the lifetime of an object.
- * This method must be explicitly called by the user whenever a new
- * reference to an object is used.
- */
- STDMETHODIMP_(UINT32) CHXFileCacheObject::AddRef(void)
- {
- MLOG_HTTP("CHXFileCacheObject::AddRef()n");
- return InterlockedIncrement(&m_RefCount);
- }
- /****************************************************************************
- * IUnknown::Release
- *
- * This routine decreases the object reference count in a thread safe
- * manner, and deletes the object if no more references to it exist. It must
- * be called explicitly by the user whenever an object is no longer needed.
- */
- STDMETHODIMP_(UINT32) CHXFileCacheObject::Release(void)
- {
- MLOG_HTTP("CHXFileCacheObject::Release()n");
- if (InterlockedDecrement(&m_RefCount) > 0)
- {
- return m_RefCount;
- }
- delete this;
- return 0;
- }
- /****************************************************************************
- * IUnknown::QueryInterface
- *
- * This routine indicates which interfaces this object supports. If a given
- * interface is supported, the object's reference count is incremented, and
- * a reference to that interface is returned. Otherwise a NULL object and
- * error code are returned. This method is called by other objects to
- * discover the functionality of this object.
- */
- STDMETHODIMP CHXFileCacheObject::QueryInterface(REFIID interfaceID,
- void** ppInterfaceObj)
- {
- MLOG_HTTP("CHXFileCacheObject::QueryInterface()n");
- // By definition all COM objects support the IUnknown interface
- if (IsEqualIID(interfaceID, IID_IUnknown))
- {
- AddRef();
- *ppInterfaceObj = (IUnknown*)(IHXCacheObject*)this;
- return HXR_OK;
- }
- // IHXCacheObject interface is supported
- else if (IsEqualIID(interfaceID, IID_IHXCacheObject))
- {
- AddRef();
- *ppInterfaceObj = (IHXCacheObject*)this;
- return HXR_OK;
- }
- // No other interfaces are supported
- *ppInterfaceObj = NULL;
- return HXR_NOINTERFACE;
- }
- //IHXCacheObject methods
- /************************************************************************
- * Method:
- *
- * IHXCacheObject::Init
- *
- * Purpose:
- *
- * Associates a cache object with the response object
- * it should notify of operation completeness.
- */
- STDMETHODIMP
- CHXFileCacheObject::Init(IHXCacheObjectResponse* /*IN*/ pCacheObjectResponse,
- UINT32 /*IN*/ ulCapacity,
- UINT32 /*IN*/ lThreshold)
- {
- MLOG_HTTP("CHXFileCacheObject::Init(Capacity = %u, Threshold = %d)n", ulCapacity, lThreshold);
- HX_RESULT res = HXR_OK;
- if(pCacheObjectResponse != NULL)
- {
- // Release any previous response objects
- if(m_pCacheObjectResponse != NULL)
- {
- m_pCacheObjectResponse->Release();
- }
- m_pCacheObjectResponse = pCacheObjectResponse;
- pCacheObjectResponse->AddRef();
-
- }
- else
- {
- res = HXR_INVALID_PARAMETER;
- }
- m_ulCapacity = ulCapacity;
- if( (lThreshold < 0) || (lThreshold >= 100) )
- {
- res = HXR_INVALID_PARAMETER;
- }
- else
- {
- m_lThreshold = lThreshold;
- }
- // Open the cache file for writing.
- m_pCacheFileHandle = fopen(m_pFileName, "wb+");
- if( m_pCacheFileHandle == NULL )
- res = HXR_FAIL;
- m_pCacheObjectResponse->InitDone(res);
- // HXR_OK from this function indicates InitDone() will be called.
- // Since this statement is executed only after the above InitDone()
- // we return HXR_OK instead of res.
- return HXR_OK;
- } // Init()
- /************************************************************************
- * Method:
- *
- * IHXCacheObject::GetThreshold
- *
- * Purpose:
- *
- * Obtain the threshold of the cache object.
- */
- STDMETHODIMP_(UINT32)
- CHXFileCacheObject::GetThreshold(void)
- {
- MLOG_HTTP("CHXFileCacheObject::GetThreshold()n");
- return m_lThreshold;
- } // GetThreshold()
- /************************************************************************
- * Method:
- *
- * IHXCacheObject::ChangeThreshold
- *
- * Purpose:
- *
- * The object keeps caching data until it is full (exhausts its
- * capacity). Once it is full, it will overwite existing cached data
- * with new data ONLY if the percentage of cached data which has been
- * read from the cache using the ReadBlock() method is *greater* than a
- * given percentage of Capacity.. This percentage is set using the SetThreshold()
- * method. In case the threshold is exceeded, the oldest added data
- * (the data with the the least offset) will be discarded and the
- * amount of data discarded is so that the remaining cached data just
- * satisfies the threshold condidtion (approximately).
- *
- * This cache object is used in the HTTP/1.0 file system plugin for
- * mobile devices and in this case, the threshold is set to 70%
- * i.e., utilizedDataPercentage = 0.7
- *
- */
- STDMETHODIMP
- CHXFileCacheObject::ChangeThreshold(UINT32 /*IN*/ lNewThreshold)
- {
- MLOG_HTTP("CHXFileCacheObject::ChangeThreshold(%d)n", lNewThreshold);
- if( (lNewThreshold < 0) || (lNewThreshold >= 100) )
- {
- return HXR_INVALID_PARAMETER;
- }
- m_pMutex->Lock();
- UINT32 lOldThreshold = m_lThreshold;
- m_lThreshold = lNewThreshold;
- HX_RESULT res = _CheckForThresholdCondition();
- if(HXR_OK != res)
- {
- // Revert back as something got messed up.
- m_lThreshold = lOldThreshold;
- }
- m_pMutex->Unlock();
- return res;
- } // ChangeThreshold()
- /************************************************************************
- * Method:
- *
- * IHXCacheObject::GetCapacity
- *
- * Purpose:
- *
- * Obtain the capacity in bytes of the cache object.
- */
- STDMETHODIMP_(UINT32)
- CHXFileCacheObject::GetCapacity(void)
- {
- MLOG_HTTP("CHXFileCacheObject::GetCapacity()n");
- return m_ulCapacity;
- } // GetCapacity()
- /************************************************************************
- * Method:
- *
- * IHXCacheObject::ChangeCapacity
- *
- * Purpose:
- *
- * Change the capacity of the cache object.
- */
- STDMETHODIMP
- CHXFileCacheObject::ChangeCapacity(UINT32 /*IN*/ newByteCount)
- {
- MLOG_HTTP("CHXFileCacheObject::ChangeCapacity(%u)n", newByteCount);
- HX_RESULT res = HXR_OK;
-
- m_pMutex->Lock();
- UINT32 ulOldCapacity = m_ulCapacity;
- m_ulCapacity = newByteCount;
- int nExcessData = m_ulUsedCapacity - newByteCount;
-
- if(nExcessData > 0)
- {
- // Discard the excess data writing to the cache file if necessary
- res = _DiscardDataFromHead((UINT32)nExcessData, TRUE);
- if(HXR_OK != res)
- {
- // Revert back to old capacity if you couldn't
- // discard data.
- m_ulCapacity = ulOldCapacity;
- }
- else
- {
- // Capacity has changed, so threshold might have been exceeded.
- res = _CheckForThresholdCondition();
- }
- }
- m_pMutex->Unlock();
- m_pCacheObjectResponse->ChangeCapacityDone(res);
-
- // HXR_OK from this function indicates ChangeCapacityDone() will be called.
- // Since this statement is executed only after the above ChangeCapacityDone()
- // we return HXR_OK instead of res.
- return HXR_OK;
- } // ChangeCapacity()
- /************************************************************************
- * Method:
- *
- * IHXCacheObject::GetUnusedCapacity
- *
- * Purpose:
- *
- * Obtain the unused capacity in bytes of the cache object.
- */
- STDMETHODIMP_(UINT32)
- CHXFileCacheObject::GetUnusedCapacity()
- {
- MLOG_HTTP("CHXFileCacheObject::GetUnusedCapacity()n");
- UINT32 ulUnusedCapacity = 0;
- m_pMutex->Lock();
- // There's data in the cache file which will be used to
- // populate the list. Will accept more data from outside
- // once I use up all data in the file.
- if(m_ulFileWriteOffset > m_ulCurrentWriteOffset)
- {
- ulUnusedCapacity = 0;
- }
- else
- {
- ulUnusedCapacity = m_ulCapacity - m_ulUsedCapacity;
- }
-
- m_pMutex->Unlock();
- return ulUnusedCapacity;
- } // GetUnusedCapacity()
- /************************************************************************
- * Method:
- *
- * IHXCacheObject::AddBlock
- *
- * Purpose:
- *
- * Adds a block of data to the cache.
- */
- STDMETHODIMP
- CHXFileCacheObject::AddBlock(IHXBuffer* /*IN*/ pBlock)
- {
- 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));
- 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;
- }
- currHead = m_pList->GetHeadPosition();
- }
- m_ulUsedCapacity -= ulDiscardedData;
- return res;
- } // _DiscardDataFromHead()
- // 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 CHXFileCacheObject::_CheckForThresholdCondition()
- {
- MLOG_HTTP("CHXFileCacheObject::_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 nExcess = (m_ulCurrentReadOffset - ulLeastOffset) -
- (INT32)(m_lThreshold * m_ulCapacity * 0.01);
- if(nExcess > 0)
- {
- if(nExcess > m_ulUsedCapacity)
- nExcess = m_ulUsedCapacity;
- res = _DiscardDataFromHead(nExcess, TRUE);
- INT32 nExtraFileData = m_ulFileWriteOffset - m_ulCurrentWriteOffset;
- if(nExtraFileData > 0)
- {
- UINT32 ulUnusedCapacity = m_ulCapacity - m_ulUsedCapacity;
- UINT32 ulFileReadData = ((UINT32)nExtraFileData > ulUnusedCapacity) ?
- ulUnusedCapacity: nExtraFileData;
- res = _CopyFromFileToTail(m_ulCurrentWriteOffset, ulFileReadData);
- }
- }
- return res;
- } // _CheckForThresholdCondition()
- // Discards exactly 'byteCount' amount of data from the tail.
- // 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::_DiscardDataFromTail(UINT32 byteCount, BOOL bWriteToFile)
- {
- MLOG_HTTP("CHXFileCacheObject::_DiscardDataFromTail(%u, %d)n", byteCount, bWriteToFile);
- HX_RESULT res = HXR_OK;
- if( (bWriteToFile) && (m_ulFileWriteOffset < m_ulCurrentWriteOffset) )
- {
- LISTPOSITION currPos = m_pList->GetTailPosition();
- while(currPos != NULL)
- {
- Info* pCurrInfo = (Info*)(m_pList->GetPrev(currPos));
- if( (m_ulFileWriteOffset >= pCurrInfo->ulOffset) &&
- (m_ulFileWriteOffset >= pCurrInfo->ulOffset + pCurrInfo->ulSize - 1) )
- {
- break;
- }
- }
- if(currPos != NULL)
- {
- Info* pCurrInfo = (Info*)(m_pList->GetAtNext(currPos));
- UINT32 ulValidData = m_ulFileWriteOffset - (pCurrInfo->ulOffset);
- UINT32 ulInvalidData = pCurrInfo->ulSize - ulValidData;
- fseek(m_pCacheFileHandle, m_ulFileWriteOffset, SEEK_SET);
- int nBytesWritten = fwrite( (void*)(pCurrInfo->pBlock->GetBuffer() + ulValidData),
- sizeof(UCHAR), ulInvalidData, m_pCacheFileHandle);
- fflush(m_pCacheFileHandle);
- m_ulFileWriteOffset += ulInvalidData;
- pCurrInfo = (Info*)(m_pList->GetNext(currPos));
- while(pCurrInfo != NULL)
- {
- int nBytesWritten = fwrite( (void*)(pCurrInfo->pBlock->GetBuffer()),
- sizeof(UCHAR), pCurrInfo->ulSize, m_pCacheFileHandle);
- fflush(m_pCacheFileHandle);
- m_ulFileWriteOffset += pCurrInfo->ulSize;
- pCurrInfo = (Info*)(m_pList->GetNext(currPos));
- }
- }
- else
- {
- res = HXR_UNEXPECTED;
- }
- }
- if(res != HXR_OK)
- return res;
- UINT32 ulDiscardedData = 0;
- Info *tailInfo = NULL;
- res = HXR_UNEXPECTED;
- LISTPOSITION currTail = m_pList->GetTailPosition();
- while(currTail != NULL)
- {
- tailInfo = (Info*)(m_pList->RemoveTail());
- UINT32 ulTailBlockSize = tailInfo->ulSize;
- if(ulDiscardedData + ulTailBlockSize <= byteCount)
- {
- tailInfo->pBlock->Release();
- delete tailInfo;
-
- ulDiscardedData += ulTailBlockSize;
- }
- else
- {
- if(ulDiscardedData + ulTailBlockSize > byteCount)
- {
- UINT32 ulValidDataSize = (ulDiscardedData + ulTailBlockSize - byteCount);
- 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*)(tailInfo->pBlock->GetBuffer()),
- ulValidDataSize );
- pNewInfo->ulOffset = tailInfo->ulOffset;
- pNewInfo->ulSize = ulValidDataSize;
- m_pList->AddTail( (void *)pNewInfo );
- tailInfo->pBlock->Release();
- delete tailInfo;
- }
- ulDiscardedData = byteCount;
- tailInfo = NULL;
- res = HXR_OK;
- break;
- }
- currTail = m_pList->GetTailPosition();
- }
- m_ulUsedCapacity -= ulDiscardedData;
- m_ulCurrentWriteOffset -= ulDiscardedData;
- return res;
- } // _DiscardDataFromTail()
- // Copies 'ulSize' amount of data from offset 'ulOffset' from
- // the cache file. The blocks are added to the Tail of the list.
- // The data is copied in blocks of size determined
- // by CAPACITY_BLOCKSIZE_RATIO. Requires that the data is present
- // in the file.
- HX_RESULT CHXFileCacheObject::_CopyFromFileToTail(UINT32 ulOffset, UINT32 ulSize)
- {
- MLOG_HTTP("CHXFileCacheObject::_CopyFromFileToTail(Offset = %u, Size = %u)n", ulOffset, ulSize);
- if(ulSize == 0)
- return HXR_OK;
- m_ulCurrentWriteOffset = ulOffset;
- UINT32 ulBlockSize = m_ulCapacity/CAPACITY_BLOCKSIZE_RATIO;
- UINT32 ulRemainderBlockSize = 0;
- UINT32 ulNumFullBlocks = ulSize/ulBlockSize;
- if((ulSize%ulBlockSize) > 0)
- {
- ulRemainderBlockSize = ulSize - ulNumFullBlocks * ulBlockSize;
- }
- HX_RESULT res = HXR_OK;
- fseek(m_pCacheFileHandle, ulOffset, SEEK_SET);
- if(ulRemainderBlockSize > 0)
- {
- IHXBuffer* pRemainderBlock = NULL;
- m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void **) &pRemainderBlock);
- if(pRemainderBlock != NULL)
- {
- res = pRemainderBlock->SetSize(ulRemainderBlockSize);
- }
- else
- {
- res = HXR_OUTOFMEMORY;
- }
- if(res == HXR_OK)
- {
- fread( (void*)(pRemainderBlock->GetBuffer()),
- sizeof(UCHAR), ulRemainderBlockSize, m_pCacheFileHandle );
- Info* pNewInfo = new Info;
- if(pNewInfo == NULL)
- {
- res = HXR_OUTOFMEMORY;
- }
- else
- {
- // The new block should be contiguous
- pNewInfo->ulOffset = m_ulCurrentWriteOffset;
- pNewInfo->ulSize = ulRemainderBlockSize;
- pNewInfo->pBlock = pRemainderBlock;
- m_pList->AddTail( (void *)pNewInfo );
- m_ulUsedCapacity += ulRemainderBlockSize;
- m_ulCurrentWriteOffset += ulRemainderBlockSize;
- }
- }
- }
- if(res != HXR_OK)
- return res;
- for(int i = 0; i < ulNumFullBlocks; i++)
- {
- IHXBuffer* pTempBlock = NULL;
- m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void **) &pTempBlock);
- if(pTempBlock != NULL)
- {
- res = pTempBlock->SetSize(ulBlockSize);
- }
- else
- {
- res = HXR_OUTOFMEMORY;
- }
- if(res == HXR_OK)
- {
- fread( (void*)(pTempBlock->GetBuffer()),
- sizeof(UCHAR), ulBlockSize, m_pCacheFileHandle );
- Info* pNewInfo = new Info;
- if(pNewInfo == NULL)
- {
- res = HXR_OUTOFMEMORY;
- }
- else
- {
- // 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 );
- }
- }
- }
- return res;
- } // _CopyFromFileToTail()
- // Copies 'ulSize' amount of data from offset 'ulOffset' from
- // the cache file. The blocks are added to the Head of the list.
- // The data is copied in blocks of size determined
- // by CAPACITY_BLOCKSIZE_RATIO. Requires that the data is present
- // in the file.
- HX_RESULT CHXFileCacheObject::_CopyFromFileToHead(UINT32 ulOffset, UINT32 ulSize)
- {
- MLOG_HTTP("CHXFileCacheObject::_CopyFromFileToHead(Offset = %u, Size = %u)n", ulOffset, ulSize);
- if(ulSize == 0)
- return HXR_OK;
- UINT32 ulBlockSize = m_ulCapacity/CAPACITY_BLOCKSIZE_RATIO;
- UINT32 ulRemainderBlockSize = 0;
- UINT32 ulNumFullBlocks = ulSize/ulBlockSize;
- if((ulSize%ulBlockSize) > 0)
- {
- ulRemainderBlockSize = ulSize - ulNumFullBlocks * ulBlockSize;
- }
- HX_RESULT res = HXR_OK;
- fseek(m_pCacheFileHandle, ulOffset + ulSize, SEEK_SET);
- UINT32 ulCurrBlockOffset = ulOffset + ulSize;
- if(ulRemainderBlockSize > 0)
- {
- IHXBuffer* pRemainderBlock = NULL;
- m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void **) &pRemainderBlock);
- if(pRemainderBlock != NULL)
- {
- res = pRemainderBlock->SetSize(ulRemainderBlockSize);
- }
- else
- {
- res = HXR_OUTOFMEMORY;
- }
- if(res == HXR_OK)
- {
- ulCurrBlockOffset -= ulRemainderBlockSize;
- fseek(m_pCacheFileHandle, ulCurrBlockOffset , SEEK_SET);
- fread( (void*)(pRemainderBlock->GetBuffer()),
- sizeof(UCHAR), ulRemainderBlockSize, m_pCacheFileHandle );
- fseek(m_pCacheFileHandle, ulCurrBlockOffset , SEEK_SET);
- Info* pNewInfo = new Info;
- if(pNewInfo == NULL)
- {
- res = HXR_OUTOFMEMORY;
- }
- else
- {
- // The new block should be contiguous
- pNewInfo->ulOffset = ulCurrBlockOffset;
- pNewInfo->ulSize = ulRemainderBlockSize;
- pNewInfo->pBlock = pRemainderBlock;
- m_pList->AddHead( (void *)pNewInfo );
- m_ulUsedCapacity += ulRemainderBlockSize;
- }
- }
- }
- if(res != HXR_OK)
- return res;
- for(int i = 0; i < ulNumFullBlocks; i++)
- {
- IHXBuffer* pTempBlock = NULL;
- m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
- (void **) &pTempBlock);
- if(pTempBlock != NULL)
- {
- res = pTempBlock->SetSize(ulBlockSize);
- }
- else
- {
- res = HXR_OUTOFMEMORY;
- }
- if(res == HXR_OK)
- {
- ulCurrBlockOffset -= ulBlockSize;
- fseek(m_pCacheFileHandle, ulCurrBlockOffset, SEEK_SET);
- fread( (void*)(pTempBlock->GetBuffer()),
- sizeof(UCHAR), ulBlockSize, m_pCacheFileHandle );
- fseek(m_pCacheFileHandle, ulCurrBlockOffset, SEEK_SET);
- Info* pNewInfo = new Info;
- if(pNewInfo == NULL)
- {
- res = HXR_OUTOFMEMORY;
- }
- else
- {
- // The new block should be contiguous
- pNewInfo->ulOffset = ulCurrBlockOffset;
- pNewInfo->ulSize = ulBlockSize;
- pNewInfo->pBlock = pTempBlock;
- m_pList->AddHead( (void *)pNewInfo );
- m_ulUsedCapacity += ulBlockSize;
- }
- }
- }
- return res;
- } // _CopyFromFileToHead()
- // Copy all the data present in the list to the local file
- HX_RESULT CHXFileCacheObject::_CopyAllDataToFile()
- {
- MLOG_HTTP("CHXFileCacheObject::_CopyAllDataToFile()n");
- if(m_pList == NULL)
- return HXR_UNEXPECTED;
- LISTPOSITION currPos = m_pList->GetHeadPosition();
- Info* pCurrInfo;
- while(currPos != NULL)
- {
- pCurrInfo = (Info *)m_pList->GetNext(currPos);
- UINT32 ulCurrBlockOffset = pCurrInfo->ulOffset;
- UINT32 ulCurrBlockSize = pCurrInfo->ulSize;
- // If data already written to file, no need to write again.
- if( (m_ulFileWriteOffset >= ulCurrBlockOffset) &&
- (m_ulFileWriteOffset <= ulCurrBlockOffset + ulCurrBlockSize - 1) )
- {
- UINT32 ulDataAlreadyWritten = m_ulFileWriteOffset - ulCurrBlockOffset;
- UINT32 ulDataToWrite = ulCurrBlockSize - ulDataAlreadyWritten;
- fseek(m_pCacheFileHandle, m_ulFileWriteOffset, SEEK_SET);
- int nBytesWritten = fwrite( (void*)(pCurrInfo->pBlock->GetBuffer() +
- ulDataAlreadyWritten), sizeof(UCHAR),
- ulDataToWrite, m_pCacheFileHandle);
- fflush(m_pCacheFileHandle);
- m_ulFileWriteOffset += ulDataToWrite;
- }
- }
- return HXR_OK;
- } // _CopyAllDataToFile()