memcache.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:25k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. #include "hxtypes.h"
  36. #include "hxcom.h"      // IUnknown
  37. #include "hxiids.h"     // GUIDs
  38. #include "hxslist.h"    // CHXSimpleList
  39. #include "hxthread.h"   // HXMutex
  40. #include "hxstring.h"   // memcpy()
  41. #include "hxcomm.h"     // IHXCommonClassFactory
  42. #include "ihxpckts.h"   // IHXBuffer
  43. #include "hxcache2.h"   // IHXCache2, IHXCacheObject, IHXCacheObjectResponse
  44. #include "memcache.h"
  45. #include "multilog.h"
  46. #include "mlog_http.h"
  47. /****************************************************************************
  48.  *  CHXMemCacheObject::CHXMemCacheObject
  49.  *
  50.  *  Constructor
  51.  */
  52. CHXMemCacheObject::CHXMemCacheObject(IHXCommonClassFactory* /*IN*/  pClassFactory)
  53.     : m_RefCount      (0),
  54.       m_pMemResponse(NULL),
  55.       m_pClassFactory(NULL),
  56.       m_ulCapacity(0),
  57.       m_lThreshold(50),
  58.       m_ulUsedCapacity(0),
  59.       m_pList(NULL),
  60.       m_ulCurrentWriteOffset(0),
  61.       m_pPendingAddBlock(NULL),
  62.       m_bInAddBlockDone(FALSE),
  63.       m_bInReadBlockDone(FALSE),
  64.       m_pMutex(NULL),
  65.       m_ulCurrentReadOffset(0)
  66. {
  67.     MLOG_HTTP("CHXMemCacheObject::CHXMemCacheObject()n");
  68.     if(pClassFactory != NULL)
  69.     {
  70.         m_pClassFactory = pClassFactory;
  71.         m_pClassFactory->AddRef();
  72.     }
  73.     m_pPendingReadInfo.ulOffset = 0;
  74.     m_pPendingReadInfo.ulLength = 0;
  75.     m_pPendingReadInfo.pBlock = NULL;
  76.     
  77.     m_pList = new CHXSimpleList;
  78.     #if defined(THREADS_SUPPORTED) || defined(_UNIX_THREADS_SUPPORTED)
  79.         HXMutex::MakeMutex(m_pMutex);
  80.     #else
  81.         HXMutex::MakeStubMutex(m_pMutex);
  82.     #endif
  83. }
  84. /****************************************************************************
  85.  *  CHXMemCacheObject::~CHXMemCacheObject
  86.  *
  87.  *  Destructor
  88.  */
  89. CHXMemCacheObject::~CHXMemCacheObject()
  90. {
  91.     MLOG_HTTP("CHXMemCacheObject::~CHXMemCacheObject()n");
  92.     m_pMutex->Lock();
  93.     // Destroy the list
  94.     if(m_pList)
  95.     {
  96.         LISTPOSITION currPos = m_pList->GetHeadPosition();
  97.         Info* currInfo;
  98.         while(currPos != NULL)
  99.         {
  100.             currInfo = (Info *)m_pList->GetNext(currPos);
  101.             currInfo->pBlock->Release();
  102.             delete currInfo;
  103.         }
  104.         delete m_pList;
  105.     }
  106.     m_pMutex->Unlock();
  107.     HX_DELETE(m_pMutex);
  108. } // ~CHXMemCacheObject()
  109. // IUnknown COM Interface Methods
  110. /****************************************************************************
  111.  *  IUnknown::AddRef
  112.  *
  113.  *  This routine increases the object reference count in a thread safe
  114.  *  manner. The reference count is used to manage the lifetime of an object.
  115.  *  This method must be explicitly called by the user whenever a new
  116.  *  reference to an object is used.
  117.  */
  118. STDMETHODIMP_(UINT32) CHXMemCacheObject::AddRef(void)
  119. {
  120.     MLOG_HTTP("CHXMemCacheObject::AddRef()n");
  121.     return InterlockedIncrement(&m_RefCount);
  122. }
  123. /****************************************************************************
  124.  *  IUnknown::Release
  125.  *
  126.  *  This routine decreases the object reference count in a thread safe
  127.  *  manner, and deletes the object if no more references to it exist. It must
  128.  *  be called explicitly by the user whenever an object is no longer needed.
  129.  */
  130. STDMETHODIMP_(UINT32) CHXMemCacheObject::Release(void)
  131. {
  132.     MLOG_HTTP("CHXMemCacheObject::Release()n");
  133.     if (InterlockedDecrement(&m_RefCount) > 0)
  134.     {
  135. return m_RefCount;
  136.     }
  137.     delete this;
  138.     return 0;
  139. }
  140. /****************************************************************************
  141.  *  IUnknown::QueryInterface
  142.  *
  143.  *  This routine indicates which interfaces this object supports. If a given
  144.  *  interface is supported, the object's reference count is incremented, and
  145.  *  a reference to that interface is returned. Otherwise a NULL object and
  146.  *  error code are returned. This method is called by other objects to
  147.  *  discover the functionality of this object.
  148.  */
  149. STDMETHODIMP CHXMemCacheObject::QueryInterface(REFIID interfaceID,
  150.        void** ppInterfaceObj)
  151. {
  152.     MLOG_HTTP("CHXMemCacheObject::QueryInterface()n");
  153.     // By definition all COM objects support the IUnknown interface
  154.     if (IsEqualIID(interfaceID, IID_IUnknown))
  155.     {
  156. AddRef();
  157. *ppInterfaceObj = (IUnknown*)(IHXCacheObject*)this;
  158. return HXR_OK;
  159.     }
  160.     // IHXCacheObject interface is supported
  161.     else if (IsEqualIID(interfaceID, IID_IHXCacheObject))
  162.     {
  163. AddRef();
  164. *ppInterfaceObj = (IHXCacheObject*)this;
  165. return HXR_OK;
  166.     }
  167.     // No other interfaces are supported
  168.     *ppInterfaceObj = NULL;
  169.     return HXR_NOINTERFACE;
  170. }
  171. //IHXCacheObject methods
  172. /************************************************************************
  173.  * Method:
  174.  *
  175.  *     IHXCacheObject::Init
  176.  *
  177.  * Purpose:
  178.  *
  179.  *     Associates a cache object with the response object
  180.  *     it should notify of operation completeness.
  181.  */
  182. STDMETHODIMP
  183. CHXMemCacheObject::Init(IHXCacheObjectResponse*     /*IN*/  pMemResponse,
  184.                         UINT32                      /*IN*/  ulCapacity,
  185.                         UINT32                      /*IN*/  lThreshold)
  186. {
  187.     MLOG_HTTP("CHXMemCacheObject::Init(Capacity = %u, Threshold = %d)n", ulCapacity, lThreshold);
  188.     HX_RESULT res = HXR_OK;
  189.     if(pMemResponse != NULL)
  190.     {
  191.         // Release any previous response objects
  192.         if(m_pMemResponse != NULL)
  193.         {
  194.             m_pMemResponse->Release();
  195.         }
  196.         m_pMemResponse = pMemResponse;
  197.         pMemResponse->AddRef();
  198.     
  199.     }
  200.     else
  201.     {
  202.         res = HXR_INVALID_PARAMETER;
  203.     }
  204.     m_ulCapacity = ulCapacity;
  205.     if( (lThreshold < 0) || (lThreshold >= 100) ) 
  206.     {
  207.         res = HXR_INVALID_PARAMETER;
  208.     }
  209.     else
  210.     {
  211.         m_lThreshold = lThreshold;
  212.     }
  213.     m_pMemResponse->InitDone(res);
  214.     // HXR_OK from this function indicates InitDone() will be called.
  215.     // Since this statement is executed only after the above InitDone()
  216.     // we return HXR_OK instead of res. 
  217.     return HXR_OK;
  218. } // Init()
  219. /************************************************************************
  220.      * Method:
  221.      *
  222.      *     IHXCacheObject::GetThreshold
  223.      *
  224.      * Purpose:
  225.      *
  226.      *     Obtain the threshold of the cache object.
  227.      */
  228. STDMETHODIMP_(UINT32)
  229. CHXMemCacheObject::GetThreshold(void)
  230. {
  231.     MLOG_HTTP("CHXFileCacheObject::GetThreshold()n"); 
  232.     return m_lThreshold;
  233. } // GetThreshold()
  234. /************************************************************************
  235.  * Method:
  236.  *
  237.  *     IHXCacheObject::ChangeThreshold
  238.  *
  239.  * Purpose:
  240.  *
  241.  *     The object keeps caching data until it is full (exhausts its 
  242.  *      capacity). Once it is full, it will overwite existing cached data
  243.  *      with new data ONLY if the percentage of cached data which has been
  244.  *      read from the cache using the ReadBlock() method is *greater* than a
  245.  *      given percentage of Capacity.. This percentage is set using the SetThreshold()
  246.  *      method. In case the threshold is exceeded, the oldest added data
  247.  *      (the data with the the least offset) will be discarded and the 
  248.  *      amount of data discarded is so that the remaining cached data just
  249.  *      satisfies the threshold condidtion (approximately).
  250.  *
  251.  *      This cache object is used in the HTTP/1.0 file system plugin for
  252.  *      mobile devices and in this case, the threshold is set to 70%
  253.  *      i.e., fNewThreshold = 0.7
  254.  *
  255.  */
  256. STDMETHODIMP
  257. CHXMemCacheObject::ChangeThreshold(UINT32  /*IN*/ lNewThreshold)
  258. {
  259.     MLOG_HTTP("CHXMemCacheObject::ChangeThreshold(%d)n", lNewThreshold); 
  260.     if( (lNewThreshold < 0) || (lNewThreshold >= 100) )
  261.     {
  262.         return HXR_INVALID_PARAMETER;
  263.     }
  264.     m_pMutex->Lock();
  265.     UINT32 lOldThreshold = m_lThreshold;
  266.     m_lThreshold = lNewThreshold;
  267.     HX_RESULT res = _CheckForThresholdCondition();
  268.     if(HXR_OK != res)
  269.     {
  270.         // Revert back as something got messed up.
  271.         m_lThreshold = lOldThreshold;
  272.     }
  273.     m_pMutex->Unlock();
  274.     return res;
  275. } // ChangeThreshold()
  276. /************************************************************************
  277.  * Method:
  278.  *
  279.  *     IHXCacheObject::GetCapacity
  280.  *
  281.  * Purpose:
  282.  *
  283.  *     Obtain the capacity in bytes of the cache object.
  284.  */
  285. STDMETHODIMP_(UINT32)
  286. CHXMemCacheObject::GetCapacity(void)
  287. {
  288.     MLOG_HTTP("CHXMemCacheObject::GetCapacity()n"); 
  289.     
  290.     return m_ulCapacity;
  291. } // GetCapacity()
  292. /************************************************************************
  293.  * Method:
  294.  *
  295.  *     IHXCacheObject::ChangeCapacity
  296.  *
  297.  * Purpose:
  298.  *
  299.  *     Change the capacity of the cache object.
  300.  */
  301. STDMETHODIMP
  302. CHXMemCacheObject::ChangeCapacity(UINT32  /*IN*/ newByteCount) 
  303. {
  304.    MLOG_HTTP("CHXMemCacheObject::ChangeCapacity(%u)n", newByteCount); 
  305.    HX_RESULT res = HXR_OK;
  306.     
  307.    m_pMutex->Lock();
  308.    UINT32 ulOldCapacity = m_ulCapacity;
  309.    m_ulCapacity = newByteCount;
  310.    int ulExcessData = m_ulUsedCapacity - newByteCount;
  311.    
  312.    if(ulExcessData > 0)
  313.    {
  314.        // Discard the excess data.
  315.        res = _DiscardData((UINT32)ulExcessData);
  316.        if(HXR_OK != res)
  317.        {
  318.            // Revert back to old capacity if you couldn't
  319.            // discard data.
  320.            m_ulCapacity = ulOldCapacity;    
  321.        }
  322.        else
  323.        {
  324.            // Capacity has changed, so threshold might have been exceeded.
  325.            res = _CheckForThresholdCondition();
  326.        }
  327.    }
  328.    m_pMutex->Unlock();
  329.    m_pMemResponse->ChangeCapacityDone(res);
  330.    
  331.    // HXR_OK from this function indicates ChangeCapacityDone() will be called.
  332.    // Since this statement is executed only after the above ChangeCapacityDone()
  333.    // we return HXR_OK instead of res. 
  334.    return HXR_OK;
  335. } // ChangeCapacity()
  336. /************************************************************************
  337.  * Method:
  338.  *
  339.  *     IHXCacheObject::GetUnusedCapacity
  340.  *
  341.  * Purpose:
  342.  *
  343.  *     Obtain the unused capacity in bytes of the cache object.
  344.  */
  345. STDMETHODIMP_(UINT32)
  346. CHXMemCacheObject::GetUnusedCapacity()
  347. {
  348.     MLOG_HTTP("CHXMemCacheObject::GetUnusedCapacity()n");
  349.     m_pMutex->Lock();
  350.     UINT32 ulUnusedCapacity = m_ulCapacity - m_ulUsedCapacity;
  351.     m_pMutex->Unlock();
  352.     return ulUnusedCapacity;
  353. } // GetUnusedCapacity()
  354. /************************************************************************
  355.  * Method:
  356.  *
  357.  *     IHXCacheObject::AddBlock
  358.  *
  359.  * Purpose:
  360.  *
  361.  *     Adds a block of data to the cache.
  362.  */
  363. STDMETHODIMP
  364. CHXMemCacheObject::AddBlock(IHXBuffer* /*IN*/ pBlock) 
  365. {
  366.     MLOG_HTTP("CHXMemCacheObject::AddBlock()n");
  367.     if(pBlock == NULL)
  368.     {
  369.         return HXR_INVALID_PARAMETER;
  370.     }
  371.     if(m_pList == NULL)
  372.         return HXR_UNEXPECTED;
  373.             
  374.     if(m_pPendingAddBlock != NULL)
  375.     {
  376.         return HXR_UNEXPECTED;
  377.     }
  378.     else
  379.     {
  380.         m_pPendingAddBlock = pBlock;
  381.         m_pPendingAddBlock->AddRef();
  382.     }
  383.     if(!m_bInAddBlockDone)
  384.     {
  385.         while(m_pPendingAddBlock)
  386.         {
  387.             IHXBuffer* pTempBlock = m_pPendingAddBlock;
  388.             m_pPendingAddBlock = NULL;
  389.             UINT32 ulBlockSize = pTempBlock->GetSize();
  390.             Info *pNewInfo = NULL;
  391.             HX_RESULT res = HXR_OK;
  392.             if(ulBlockSize != 0)
  393.             {
  394.                 m_pMutex->Lock(); 
  395.            
  396.                 // Can you accomodate this data?
  397.                 if(m_ulUsedCapacity + ulBlockSize > m_ulCapacity)
  398.                 {
  399.                     res = HXR_OUTOFMEMORY;
  400.                 }
  401.                 else
  402.                 {
  403.                     pNewInfo = new Info;
  404.                     if(pNewInfo == NULL)
  405.                         res = HXR_OUTOFMEMORY;
  406.                 }
  407.                 if(HXR_OK == res)
  408.                 {
  409.                     // The new block should be contiguous
  410.                     pNewInfo->ulOffset = m_ulCurrentWriteOffset;
  411.                     pNewInfo->ulSize = ulBlockSize;
  412.                     pNewInfo->pBlock = pTempBlock;
  413.                     m_ulUsedCapacity += ulBlockSize;
  414.                     m_ulCurrentWriteOffset += ulBlockSize;
  415.                     m_pList->AddTail( (void *)pNewInfo );
  416.                 }
  417.             
  418.                 m_pMutex->Unlock();
  419.             }
  420.             else
  421.             {
  422.                 pTempBlock->Release();
  423.             }
  424.             m_bInAddBlockDone = TRUE;
  425.             m_pMemResponse->AddBlockDone(res);
  426.             m_bInAddBlockDone = FALSE;
  427.         } // while
  428.     }
  429.     return HXR_OK;
  430. } // AddBlock()
  431. /************************************************************************
  432.  * Method:
  433.  *
  434.  *     IHXCacheObject::VerifyBlock
  435.  *
  436.  * Purpose:
  437.  *
  438.  *     Verify that a block of data is in the cache.
  439.  */
  440. STDMETHODIMP
  441. CHXMemCacheObject::VerifyBlock(UINT32 /*IN*/ ulBlockOffset,
  442.  UINT32 /*IN*/ ulBlockLength)
  443. {
  444.     MLOG_HTTP("CHXMemCacheObject::VeifyBlock()n");
  445.     if(m_pList == NULL)
  446.         return HXR_UNEXPECTED;
  447.     m_pMutex->Lock();
  448.     
  449.     // Critical Section starts
  450.     BOOL bExists = TRUE;
  451.     if(m_ulUsedCapacity == 0)
  452.     {
  453.         bExists = FALSE;
  454.     }
  455.     else
  456.     {
  457.         UINT32 ulLeastOffset = m_ulCurrentWriteOffset - m_ulUsedCapacity;
  458.         UINT32 ulHighestOffset = m_ulCurrentWriteOffset - 1;
  459.         
  460.         BOOL bStartExists = (ulBlockOffset >= ulLeastOffset) && 
  461.                             (ulBlockOffset <= ulHighestOffset);
  462.         BOOL bEndExists = (ulBlockOffset + ulBlockLength - 1 >= ulLeastOffset) &&
  463.                           (ulBlockOffset + ulBlockLength - 1 <= ulHighestOffset);
  464.         bExists = bStartExists && bEndExists;
  465.     }
  466.     // Critical section ends
  467.     m_pMutex->Unlock();
  468.     m_pMemResponse->VerifyBlockDone(bExists);
  469.     return HXR_OK;
  470. } // VerifyBlock()
  471. /************************************************************************
  472.  * Method:
  473.  *
  474.  *     IHXCacheObject::ReadBlock
  475.  *
  476.  * Purpose:
  477.  *
  478.  *     Read a block out of the cache.
  479.  */
  480. STDMETHODIMP
  481. CHXMemCacheObject::ReadBlock(UINT32 /*IN*/ ulBlockOffset,
  482.             UINT32 /*IN*/ ulBlockLength)
  483. {
  484.     MLOG_HTTP("CHXMemCacheObject::ReadBlock(Offset = %u, Length = %u)n", ulBlockOffset, ulBlockLength);
  485.     if(m_pList == NULL)
  486.         return HXR_UNEXPECTED;
  487.     if(m_pPendingReadInfo.pBlock != NULL)
  488.         return HXR_UNEXPECTED;
  489.     m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
  490.                      (void **) &m_pPendingReadInfo.pBlock);
  491.     if(m_pPendingReadInfo.pBlock == NULL)
  492.         return HXR_OUTOFMEMORY;
  493.     HX_RESULT res = m_pPendingReadInfo.pBlock->SetSize(ulBlockLength);
  494.     if(res != HXR_OK)
  495.     {
  496.         m_pPendingReadInfo.pBlock->Release();
  497.         m_pPendingReadInfo.pBlock = NULL;
  498.         return res;
  499.     }
  500.     m_pPendingReadInfo.ulLength = ulBlockLength;
  501.     m_pPendingReadInfo.ulOffset = ulBlockOffset;
  502.     if(!m_bInReadBlockDone)
  503.     {
  504.         while(m_pPendingReadInfo.pBlock)
  505.         {
  506.             HX_RESULT res2 = HXR_OK;
  507.             // To prepare for the possibilty of ReadBlock()
  508.             // being called from ReadBlockDone()
  509.             IHXBuffer* pTempBlock = m_pPendingReadInfo.pBlock;
  510.             m_pPendingReadInfo.pBlock = NULL;
  511.             UINT32 ulTempLength = m_pPendingReadInfo.ulLength;
  512.             m_pPendingReadInfo.ulLength = 0;
  513.             UINT32 ulTempOffset = m_pPendingReadInfo.ulOffset;
  514.             m_pPendingReadInfo.ulOffset = 0;
  515.             m_pMutex->Lock();
  516.             UINT32 ulLeastOffset = m_ulCurrentWriteOffset - m_ulUsedCapacity; 
  517.             UINT32 ulHighestOffset = m_ulCurrentWriteOffset - 1;
  518.             if(m_ulUsedCapacity == 0)
  519.             {
  520.                 if(ulTempOffset >= m_ulCurrentWriteOffset)
  521.                     res2 = HXR_INCOMPLETE;
  522.                 else
  523.                     res2 = HXR_FAIL;
  524.                     
  525.                 HX_RELEASE(pTempBlock);
  526.                 pTempBlock = NULL;
  527.             }
  528.             else if(ulTempOffset < ulLeastOffset)
  529.             {
  530.                 res2 = HXR_FAIL;
  531.                 HX_RELEASE(pTempBlock);
  532.                 pTempBlock = NULL;
  533.             }
  534.             else if(ulTempOffset > ulHighestOffset)
  535.             {
  536.                 res2 = HXR_INCOMPLETE;
  537.                 HX_RELEASE(pTempBlock);
  538.                 pTempBlock = NULL;
  539.                 // If 'forward data' requested, mark all data as read so
  540.                 // that old data can be discarded to make space for new data.
  541.                 //m_ulCurrentReadOffset = ulHighestOffset + 1; 
  542.                 m_ulCurrentReadOffset = ulTempOffset;
  543.                 _CheckForThresholdCondition();
  544.             }
  545.             else
  546.             {
  547.                 // Fill the pTempBlock with data from the list
  548.             
  549.                 UCHAR* ucTempBlockData = pTempBlock->GetBuffer();
  550.                 UINT32 ulBytesReadFromList = 0;
  551.                 LISTPOSITION currPos = m_pList->GetHeadPosition();
  552.                 Info* currInfo;
  553.                 while(currPos != NULL)
  554.                 {   
  555.                     currInfo = (Info *)m_pList->GetNext(currPos);
  556.                     UINT32 ulCurrLowOffset = currInfo->ulOffset;
  557.                     UINT32 ulCurrHighOffset = currInfo->ulOffset + currInfo->ulSize - 1;
  558.                     UCHAR* ucCurrBlockData = currInfo->pBlock->GetBuffer();
  559.                     if( (ulTempOffset >= ulCurrLowOffset) && (ulTempOffset <= ulCurrHighOffset) )
  560.                     {
  561.                         UINT32 ulMatchSize = ( (ulCurrHighOffset - ulTempOffset + 1) < ulTempLength ) ?
  562.                                                 ulCurrHighOffset - ulTempOffset + 1 : ulTempLength;
  563.                         memcpy((void*)(ucTempBlockData + ulBytesReadFromList),
  564.                                 (void*)(ucCurrBlockData + ulTempOffset - ulCurrLowOffset), ulMatchSize);
  565.                         ulBytesReadFromList += ulMatchSize;
  566.                         ulTempOffset += ulMatchSize;
  567.                         ulTempLength -= ulMatchSize;
  568.                         if(0 == ulTempLength)
  569.                             break;
  570.                     }
  571.                 }
  572.                 if(ulTempLength > 0)
  573.                 {
  574.                     res2 = HXR_INCOMPLETE;
  575.                     pTempBlock->SetSize(ulBytesReadFromList);   
  576.                 }
  577.                 else
  578.                 {
  579.                     res2 = HXR_OK;
  580.                 }
  581.                 m_ulCurrentReadOffset = ulTempOffset;
  582.                 _CheckForThresholdCondition();
  583.             }
  584.             m_pMutex->Unlock();
  585.             m_bInReadBlockDone = TRUE;
  586.             m_pMemResponse->ReadBlockDone(res2, pTempBlock);
  587.             m_bInReadBlockDone = FALSE;
  588.             
  589.             HX_RELEASE(pTempBlock);
  590.         }
  591.     }
  592.     return HXR_OK;
  593. } // ReadBlock()
  594. /************************************************************************
  595.  * Method:
  596.  *     IHXCacheObject::Flush
  597.  *
  598.  * Purpose:
  599.  *
  600.  *     Releases all data buffers cached in the object. The object now
  601.  *      gets to a same state as when it was newly created. After flushine,
  602.  *     the object can be used for reading/writing as before.
  603.  */
  604. STDMETHODIMP
  605. CHXMemCacheObject::Flush(void) 
  606. {
  607.     MLOG_HTTP("CHXMemCacheObject::Flush()n");
  608.     if(!m_pList)
  609.         return HXR_UNEXPECTED;;
  610.     
  611.     m_pMutex->Lock();
  612.     LISTPOSITION currPos = m_pList->GetHeadPosition();
  613.     Info* currInfo;
  614.     while(currPos != NULL)
  615.     {
  616.         currInfo = (Info *)m_pList->GetNext(currPos);
  617.         currInfo->pBlock->Release();
  618.         delete currInfo;
  619.     }
  620.     m_pList->RemoveAll();
  621.     m_ulUsedCapacity = 0;
  622.     m_ulCurrentWriteOffset = 0;
  623.     m_ulCurrentReadOffset = 0;
  624.     m_pMutex->Unlock();
  625.     m_pMemResponse->FlushDone(HXR_OK);
  626.     return HXR_OK;
  627. } // Flush()
  628. /************************************************************************
  629.  * Method:
  630.  *
  631.  *     IHXCacheObject::IsFull
  632.  *
  633.  * Purpose:
  634.  *
  635.  *     Can the cache object accept any more data for storage?
  636.  */
  637. STDMETHODIMP_(BOOL)
  638. CHXMemCacheObject::IsFull()
  639. {
  640.     MLOG_HTTP("CHXMemCacheObject::IsFull()n");
  641.     m_pMutex->Lock();
  642.     BOOL bIsFull = TRUE;
  643.     if(m_ulUsedCapacity < m_ulCapacity)
  644.         bIsFull = FALSE;
  645.     
  646.     m_pMutex->Unlock();
  647.     return bIsFull;
  648. } // IsFull()
  649. /************************************************************************
  650.  * Method:
  651.  *
  652.  *     IHXCacheObject::IsEmpty
  653.  *
  654.  * Purpose:
  655.  *
  656.  *     Does the cache object have any data stored?
  657.  */
  658. STDMETHODIMP_(BOOL)
  659. CHXMemCacheObject::IsEmpty()
  660. {
  661.     MLOG_HTTP("CHXMemCacheObject::IsEmpty()n");
  662.     if(m_ulUsedCapacity == 0)
  663.         return TRUE;
  664.     else
  665.         return FALSE;
  666. } // IsEmpty()
  667. // Discards exactly 'byteCount' amount of oldest data.
  668. // Note that this method is not thread safe. The caller has to take 
  669. // care of locking common data structures before calling this method.
  670. HX_RESULT CHXMemCacheObject::_DiscardData(UINT32 byteCount)
  671. {
  672.     MLOG_HTTP("CHXMemCacheObject::_DiscardData(%u)n", byteCount);
  673.     HX_RESULT res = HXR_UNEXPECTED;
  674.     UINT32 ulDiscardedData = 0;
  675.     LISTPOSITION currHeadPos = NULL;
  676.     Info *headInfo = NULL;
  677.     while( (currHeadPos = m_pList->GetHeadPosition())!= NULL )
  678.     {
  679.         headInfo = (Info*)(m_pList->RemoveHead());
  680.         UINT32 ulHeadBlockSize = headInfo->ulSize;
  681.         if(ulDiscardedData + ulHeadBlockSize <= byteCount)
  682.         {
  683.             headInfo->pBlock->Release();
  684.             delete headInfo;
  685.             
  686.             ulDiscardedData += ulHeadBlockSize;
  687.         }
  688.         else
  689.         {
  690.             if(ulDiscardedData + ulHeadBlockSize > byteCount)
  691.             {
  692.                 UINT32 ulValidDataSize = (ulDiscardedData + ulHeadBlockSize - byteCount);
  693.                 UINT32 ulInvalidDataSize = ulHeadBlockSize - ulValidDataSize;
  694.                 Info *pNewInfo = new Info;
  695.                 if(pNewInfo == NULL)
  696.                 {
  697.                    res = HXR_OUTOFMEMORY;
  698.                    break;
  699.                 }
  700.                 m_pClassFactory->CreateInstance(CLSID_IHXBuffer,
  701.                                                (void **) &(pNewInfo->pBlock));
  702.                 if(pNewInfo->pBlock == NULL)
  703.                     break;
  704.                 res = pNewInfo->pBlock->SetSize(ulValidDataSize);
  705.                 if(res != HXR_OK)
  706.                     break;
  707.                 memcpy( (void*)(pNewInfo->pBlock->GetBuffer()),
  708.                         (void*)(headInfo->pBlock->GetBuffer()+ ulInvalidDataSize),
  709.                         ulValidDataSize );
  710.                 pNewInfo->ulOffset = headInfo->ulOffset + ulInvalidDataSize;
  711.                 pNewInfo->ulSize = ulValidDataSize;
  712.                 m_pList->AddHead( (void *)pNewInfo );
  713.                 headInfo->pBlock->Release();
  714.                 delete headInfo;
  715.             }
  716.             ulDiscardedData = byteCount;
  717.             headInfo = NULL;
  718.             res = HXR_OK;
  719.             break;
  720.         }
  721.     }
  722.     m_ulUsedCapacity -= ulDiscardedData;
  723.     return res;
  724. }
  725. // Check if utilizedData has exceeded THRESHOLD. If yes, discard 
  726. // appropriate amount of data. Note that this
  727. // method is not thread safe. The caller has to take care of 
  728. // locking common data structures before calling this method.
  729. HX_RESULT CHXMemCacheObject::_CheckForThresholdCondition()
  730. {
  731.     MLOG_HTTP("CHXMemCacheObject::_CheckForThresholdCondition()n");
  732.     if(m_ulUsedCapacity == 0)
  733.     {
  734.         return HXR_OK;
  735.     }
  736.     UINT32 ulLeastOffset = m_ulCurrentWriteOffset - m_ulUsedCapacity;
  737.     UINT32 ulHighestOffset = m_ulCurrentWriteOffset - 1;
  738.     HX_RESULT res = HXR_OK;
  739.     INT32 ulExcess = (m_ulCurrentReadOffset - ulLeastOffset) - 
  740.                       (INT32)(m_lThreshold * m_ulCapacity * 0.01);
  741.     if(ulExcess > 0)
  742.     {
  743.         if(ulExcess > m_ulUsedCapacity)
  744.             ulExcess = m_ulUsedCapacity; 
  745.         res = _DiscardData(ulExcess);
  746.     }
  747.     return res;
  748. } // _CheckForThresholdCondition()