📄 filecache.cpp
字号:
/* ***** 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -