📄 memcache.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 "memcache.h"
#include "multilog.h"
#include "mlog_http.h"
/****************************************************************************
* CHXMemCacheObject::CHXMemCacheObject
*
* Constructor
*/
CHXMemCacheObject::CHXMemCacheObject(IHXCommonClassFactory* /*IN*/ pClassFactory)
: m_RefCount (0),
m_pMemResponse(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)
{
MLOG_HTTP("CHXMemCacheObject::CHXMemCacheObject()\n");
if(pClassFactory != NULL)
{
m_pClassFactory = pClassFactory;
m_pClassFactory->AddRef();
}
m_pPendingReadInfo.ulOffset = 0;
m_pPendingReadInfo.ulLength = 0;
m_pPendingReadInfo.pBlock = NULL;
m_pList = new CHXSimpleList;
#if defined(THREADS_SUPPORTED) || defined(_UNIX_THREADS_SUPPORTED)
HXMutex::MakeMutex(m_pMutex);
#else
HXMutex::MakeStubMutex(m_pMutex);
#endif
}
/****************************************************************************
* CHXMemCacheObject::~CHXMemCacheObject
*
* Destructor
*/
CHXMemCacheObject::~CHXMemCacheObject()
{
MLOG_HTTP("CHXMemCacheObject::~CHXMemCacheObject()\n");
m_pMutex->Lock();
// 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);
} // ~CHXMemCacheObject()
// 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) CHXMemCacheObject::AddRef(void)
{
MLOG_HTTP("CHXMemCacheObject::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) CHXMemCacheObject::Release(void)
{
MLOG_HTTP("CHXMemCacheObject::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 CHXMemCacheObject::QueryInterface(REFIID interfaceID,
void** ppInterfaceObj)
{
MLOG_HTTP("CHXMemCacheObject::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
CHXMemCacheObject::Init(IHXCacheObjectResponse* /*IN*/ pMemResponse,
UINT32 /*IN*/ ulCapacity,
UINT32 /*IN*/ lThreshold)
{
MLOG_HTTP("CHXMemCacheObject::Init(Capacity = %u, Threshold = %d)\n", ulCapacity, lThreshold);
HX_RESULT res = HXR_OK;
if(pMemResponse != NULL)
{
// Release any previous response objects
if(m_pMemResponse != NULL)
{
m_pMemResponse->Release();
}
m_pMemResponse = pMemResponse;
pMemResponse->AddRef();
}
else
{
res = HXR_INVALID_PARAMETER;
}
m_ulCapacity = ulCapacity;
if( (lThreshold < 0) || (lThreshold >= 100) )
{
res = HXR_INVALID_PARAMETER;
}
else
{
m_lThreshold = lThreshold;
}
m_pMemResponse->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)
CHXMemCacheObject::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., fNewThreshold = 0.7
*
*/
STDMETHODIMP
CHXMemCacheObject::ChangeThreshold(UINT32 /*IN*/ lNewThreshold)
{
MLOG_HTTP("CHXMemCacheObject::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)
CHXMemCacheObject::GetCapacity(void)
{
MLOG_HTTP("CHXMemCacheObject::GetCapacity()\n");
return m_ulCapacity;
} // GetCapacity()
/************************************************************************
* Method:
*
* IHXCacheObject::ChangeCapacity
*
* Purpose:
*
* Change the capacity of the cache object.
*/
STDMETHODIMP
CHXMemCacheObject::ChangeCapacity(UINT32 /*IN*/ newByteCount)
{
MLOG_HTTP("CHXMemCacheObject::ChangeCapacity(%u)\n", newByteCount);
HX_RESULT res = HXR_OK;
m_pMutex->Lock();
UINT32 ulOldCapacity = m_ulCapacity;
m_ulCapacity = newByteCount;
int ulExcessData = m_ulUsedCapacity - newByteCount;
if(ulExcessData > 0)
{
// Discard the excess data.
res = _DiscardData((UINT32)ulExcessData);
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_pMemResponse->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)
CHXMemCacheObject::GetUnusedCapacity()
{
MLOG_HTTP("CHXMemCacheObject::GetUnusedCapacity()\n");
m_pMutex->Lock();
UINT32 ulUnusedCapacity = m_ulCapacity - m_ulUsedCapacity;
m_pMutex->Unlock();
return ulUnusedCapacity;
} // GetUnusedCapacity()
/************************************************************************
* Method:
*
* IHXCacheObject::AddBlock
*
* Purpose:
*
* Adds a block of data to the cache.
*/
STDMETHODIMP
CHXMemCacheObject::AddBlock(IHXBuffer* /*IN*/ pBlock)
{
MLOG_HTTP("CHXMemCacheObject::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)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -