`
wooce
  • 浏览: 184159 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

一个HASH CACHE类

    博客分类:
  • C++
阅读更多
原作者是kaman, 我作了一点改进。
#ifndef _IHASHCACHE_H
#define _IHASHCACHE_H

#include "icache.h"
#include "imutexlock.h"
#include "ierror.h"
#include "iexception.h"

template <class IObject, class IKey>
class IHashCache;

// A class derived from 'ICacheNode', it cooperates with 'IHashCache'. 
// @Description:
//		'IHashCacheNode'是'IHashCache'的结点类型,继承了'ICacheNode'与'IHashCache'配对。
//	可以储存结点有效期和Hash,LRU链等信息。
// @MT-Safe:
//		Yes / Required.
// @Notes:
//		Equality operator and relation equality operator should be overloaded.
// @SeeAlso:
//		'IHashCache', 'ICacheNode'
template <
class IObject, 
//The key type of this cache.
class IKey
>
class IHashCacheNode : public ICacheNode<IObject, IKey>
{
public:
    // Constructor.
    // @Parameters:
    //		%Object			The Object to be stored.
    //		%Key			The key assoicated the object.
    //		%nSize			The size of the object.
    //		%nTimeToLive	The time the object lives in the cache. -1 is permanence.
    IHashCacheNode (IObject Object, const IKey &Key, long nSize = 0, time_t nTimeToLive = -1);

    // virtual destructor.
    virtual  ~IHashCacheNode();

    // Make a new copy of the object in this cachenode and export it.
    virtual IObject GetObject();

    // Return the key in this cachenode .
    const IKey &GetKey();

private:
    // Do the initial work for IHashCache.
    void Init (const IKey &Key);    

    // Prevent the cachenode from implicit conversion.
    IHashCacheNode(const IHashCacheNode< IObject,IKey > &right) {};

    // Prevent the cachenode from doing equality operation.
    IHashCacheNode< IObject,IKey > & operator=(const IHashCacheNode< IObject,IKey > &right) {};

public:     
    // The next cachenode in hash table.
    IHashCacheNode *m_pHashNextNode;

    // The previous cachenode in hash table.
    IHashCacheNode *m_pHashPrevNode;

    // The next cachenode in LRU list(access list).
    IHashCacheNode *m_pAccessListNextNode;

    // The previous cachenode in LRU list(access list).
    IHashCacheNode *m_pAccessListPrevNode;

    // The accessed time of this cachenode.
    // @Description:
    //		Increment whenever this cachenode was exported.
    //	When this value equals the adjust rate which user defined, the LRU 
    //	list will be adjusted, and this value will be set to zero.
    int m_nHits;

    // The context of the object which is stored.
    IObject m_Object;

    // The key associated with this cachenode.
    IKey m_Key;

    friend class IHashCache<IObject, IKey>;
};

template <class IObject, class IKey>
IHashCacheNode<IObject,IKey>::IHashCacheNode (IObject Object, const IKey &Key, long nSize, time_t nTimeToLive):ICacheNode<IObject, IKey>(nSize,nTimeToLive)
{
    m_Object = Object;
    Init( Key );
}


template <class IObject, class IKey>
IHashCacheNode<IObject,IKey>::~IHashCacheNode()
{
}

template <class IObject, class IKey>
void IHashCacheNode<IObject,IKey>::Init (const IKey &Key)
{
    m_Key = Key;

    m_pHashNextNode = NULL;
    m_pHashPrevNode = NULL;
    m_pAccessListNextNode = NULL;
    m_pAccessListPrevNode = NULL;

    m_nHits = 0;
}

template <class IObject, class IKey>
const IKey &IHashCacheNode<IObject, IKey>::GetKey()
{
    return m_Key;
}

template <class IObject, class IKey>
IObject IHashCacheNode<IObject, IKey>::GetObject()
{
    return m_Object;
}


#define IHashCacheNodeType IHashCacheNode<IObject, IKey>

// 'IHashCache'类继承了'ICache'类,并实现了相应的存取和筛选算法。
// @Description:
//		对于Cache的存取,'IHashCache'采用了散列算法,根据用户所提供的散列函数
//	对新储存的结点进行散列。至于筛选算法,则采用最近最少使用LRU算法,存
//	入CACHE的结点组成一条LRU链,用者可以指定改变LRU结点顺序的结点调用次
//	数。每当CACHE装满或结点过期时,'IHashCache'就会从LRU链头开始删除,以
//	滕出空间放入新结点。 用户还可指定每次删除CACHE时一次性删除的结点数。
// @Usage:
//		Overide '.Hash()' function.
// @Notes:
//		Equality operator and relation equality operator should be overloaded.
// @MT-Safe:
//		Yes / Required.
// @SeeAlso:
//		'ICache', IHashCacheNode'
template <
class IObject, 
//The key type of this cache.
class IKey
>
class IHashCache: public ICache<IObject, IKey>
{
public:
    // Default constructor.
    IHashCache();

    // Constructor with configuring parameters.
    // @Parameters:
    //		%nMaxMem			The max memory (bytes) the cache can use.
    //		%nMaxCacheBlock		The number of blocks in the hash table.
    //		%nMaxCacheSize		The max number of nodes can be stored.
    //		%nNumToReap			The number of node being deleted every time 
    //							invoking '.Reap()'
    //		%nAjustRate			The time of hiting that will change LRU list.
    IHashCache( long nMaxMem, int nMaxCacheBlock, int nMaxCacheSize, int nNumToReap, int nAdjustRate );

    // Destructor.
    virtual ~IHashCache();

    // Reset IHashCache's parameters.
    virtual void Set(long nMaxMem, int nMaxCacheBlock, int nMaxCacheSize, int nNumToReap, int nAdjustRate );

    // Store an object to the cache with the specified key.
    bool Store (IObject Object, const IKey &Key, long nUsedMem = 0, time_t nTimeToLive = -1);

    // Fetch an object according to the key specified. ICache 
    // will return a copy of the object.
    IObject Fetch (const IKey &Key);

    // Added by Wooce
    IObject FetchAndCache(const IKey &Key);

    // Delete an object from the cache according to the key specified.
    // @Description:
    //		If the key didn't exist, it wouldn't delete anything and return 
    //	true. If the key matched the item in the cache, it would delete 
    //	it from the cache and return true. Return false if something wrong 
    //	happens.
    bool Delete (const IKey &Key);

    // Pure abstract function.
    // The hash function that the derived class should overload for the 
    // hash algorthim use.
    virtual unsigned Hash( const IKey &Key ) = 0;

    // 对Cache中的内容进行遍历。
    void TraverseContainer();

    // 对LRU链进行遍历。
    void TraverseXX();

    // 回调函数,在运行TraverseContainer时对每个结点回调,可被继承类重载。
    virtual void OnTraverseContainer(IHashCacheNodeType *pNode) {};

    // 回调函数,在运行TraverseXX时对每个结点回调,可被继承类重载。
    virtual void OnTraverseXX(IHashCacheNodeType *pNode) {};

    // Get the count of objects stored in the cache.
    int GetObjectCount ();

protected:
    //Added by Wooce
    //   If an object not exists in the cache, we can use this function to get the object from other place such as database,etc
    virtual void GetCacheObject( const IKey &Key,IObject& object )=0;

    // 跟据指定的KEY在CACHE中找寻相应的结点。
    IHashCacheNodeType * SearchNode (const IKey &Key);

    // 删除CACHE中结点。
    int Reap ();

    // CACHE被装满时返回TRUE。
    bool IsFull ();

    // 对HASH表中KEY对应的行进行锁定。
    void ReadLockNodeByKey (const IKey &Key);

    void WriteLockNodeByKey (const IKey &Key);

	int TryLockWhenCache(const IKey &Key);

    // 对HASH表中KEY对应的行进行解锁。
    void UnLockNodeByKey (const IKey &Key);

    // 把结点连到HASH表中。
    bool AddNodeToContainer (IHashCacheNodeType *pNode);

    // 把结点从HASH表中移除。
    bool DelNodeFromContainer (IHashCacheNodeType *pNode);

    // 把结点连入LRU链。
    bool AddNodeToXX (IHashCacheNodeType *pNode);

    // 把结点从HASH表中移除。
    bool DelNodeFromXX (IHashCacheNodeType *pNode);

    // 对整条LRU链进行封锁。
    void LockXX ();

    // 对LRU链进行解锁。
    void UnLockXX ();

    // 调整LRU链。
    bool AdjustNodeFromXX (IHashCacheNodeType *pNode);

    // 结点过期时的处理函数。
    bool TimeOutHandler (IHashCacheNodeType *pNode);

    // 把指定的结点链入IHashCache中.
    bool StoreNode (IHashCacheNodeType *pNode);

    // 删除指定结点与IHashCache的链结。
    void DeleteNode( IHashCacheNodeType* pNode );

    // 增加结点时的回调函数,在结点插入前调用。
    virtual void OnInsertNode (IHashCacheNodeType *pNode) {};

    // 删除结点时的回调函数,在结点删除前调用。
    virtual void OnDeleteNode (IHashCacheNodeType *pNode) {};

    // 提取结点时的回调函数,在找到结点且返回之前调用。
    virtual void OnFetchNode (ICacheNodeType *pNode) {};

    // 增加结点时封锁整个Cache,目的是为了保持Cache中结点数和所用内存空间
    // 与实际存入的结点相符合,不会出现结点数虚增,即结点数已增加而结点还在
    // 等符插入。
    void LockStore();

    // LockStore()的解锁操作。
    void UnLockStore();

private:
    // Initialize IHashCache's parameters.
    void Init( long nMaxMem, int nMaxCacheBlock, int nMaxCacheSize, int nNumToReap, int nAdjustRate );

    // 把'IHashCache'中占用的内存去除。
    void Destory();

protected:
    // The maximum memory can be used in the cache.
    long    m_nMaxMem;

    // The used memory used by the cachenode already in the cache.
    long    m_nUsedMem;

    // The max cachenode count can be stored in the cache.
    int     m_nCacheSize;

    // The cachenode count already stored in the cache.
    int     m_nCacheCount;

    // Max blocks in hash
    int     m_nCacheBlocks; 

    // How many objects should be cleared in one reap action
    int     m_nNumToReap;

    // Only move the object to the end of access list when it was 
    //hit m_nAdjustRate times
    int     m_nAdjustRate;      

    // The head pointers pointed to the first element in each hash table row.
    IHashCacheNodeType**        m_apCacheHead;

    // The tail pointers pointed to the last element in each hash table row.
    IHashCacheNodeType**        m_apCacheTail;

    // The head pointer pointed to the first element of LRU list(access list).
    IHashCacheNodeType*     m_pAccessListHead;

    // The tail pointer pointed to the last element of LRU list(access list).
    IHashCacheNodeType*     m_pAccessListTail;

    // An array of locks used for locking a specified row in hash table.
    // It will be used at the time adjusting the hash table which is no need to 
    // lock the whole cache.
    IRWLock*    m_LockHash;

    // A lock which locks the whole cache when adjusting LRU list.
    ILock   m_LockAccessList;

    // A lock used when invoking store function.
    ILock   m_LockStore;

};

template <class IObject, class IKey>
IHashCache<IObject, IKey>::IHashCache()
{
    m_nMaxMem = 0;
    m_nUsedMem = 0;
    m_nCacheSize = 0;
    m_nCacheCount = 0;
    m_nCacheBlocks = 0;
    m_nNumToReap = 0;
    m_nAdjustRate = 0;

    m_apCacheHead = NULL;
    m_apCacheTail = NULL;
    m_pAccessListHead = NULL;
    m_pAccessListTail = NULL;
    m_LockHash = NULL;
}

template <class IObject, class IKey>
IHashCache<IObject, IKey>::IHashCache( long nMaxMem, int nMaxCacheBlock, int nMaxCacheSize, int nNumToReap, int nAdjustRate )
{
    Init( nMaxMem, nMaxCacheBlock, nMaxCacheSize, nNumToReap, nAdjustRate );
}

template <class IObject, class IKey>
IHashCache<IObject,IKey>::~IHashCache()
{
    Destory();
}

template <class IObject, class IKey>
void IHashCache<IObject, IKey>::Init( long nMaxMem, int nMaxCacheBlock, int nMaxCacheSize, int nNumToReap, int nAdjustRate )
{
    try
    {
        m_apCacheHead = m_apCacheTail = NULL;
        m_LockHash = NULL;
        XNew( m_apCacheHead , IHashCacheNodeType* [ nMaxCacheBlock ] );
        XNew( m_apCacheTail , IHashCacheNodeType* [ nMaxCacheBlock ] );

        m_LockHash = new IRWLock [ nMaxCacheBlock ];
        if ( m_LockHash == NULL )
            throw IException( MEMNOTENOUGH, "Not enough memory" );
    } catch (...)
    {
        if ( m_apCacheHead != NULL )
            delete[] m_apCacheHead;
        if ( m_apCacheTail != NULL )
            delete[] m_apCacheTail;
        if ( m_LockHash != NULL )
            delete[] m_LockHash;
        throw;
    }
    for ( int i=0; i<nMaxCacheBlock; i++ )
        m_apCacheHead[ i ] = m_apCacheTail[ i ] = NULL;

    m_pAccessListHead = NULL;
    m_pAccessListTail = NULL;

    m_nMaxMem = nMaxMem;
    m_nUsedMem = 0;
    m_nCacheSize = nMaxCacheSize;
    m_nCacheCount = 0;
    m_nCacheBlocks = nMaxCacheBlock;
    m_nNumToReap = nNumToReap;
    m_nAdjustRate = nAdjustRate;    
}

template <class IObject, class IKey>
void IHashCache<IObject, IKey>::Destory()
{
    IHashCacheNodeType *p, *p1;
    if ( m_apCacheHead != NULL )
    {
        for ( int i=0; i < m_nCacheBlocks ; i++ )
        {
            p = m_apCacheHead[i];
            while ( p != NULL )
            {
                p1 = p->m_pHashNextNode;
                delete p;
                p = p1;
            }
        }
        delete m_apCacheHead;
    }
    if ( m_apCacheTail != NULL )
        delete m_apCacheTail;
    if ( m_LockHash != NULL )
        delete[] m_LockHash;
}


template <class IObject, class IKey>
void IHashCache<IObject, IKey>::Set(long nMaxMem, int nMaxCacheBlock, int nMaxCacheSize, int nNumToReap, int nAdjustRate )
{
    Destory();
    Init( nMaxMem, nMaxCacheBlock, nMaxCacheSize, nNumToReap, nAdjustRate );
}

template <class IObject, class IKey>
bool IHashCache<IObject,IKey>::Store( IObject Object, const IKey& Key, long nUsedMem, time_t nTimeToLive )
{
    IHashCacheNodeType *pNode;

    try
    {
        XNew( pNode , IHashCacheNodeType( Object, Key, nUsedMem, nTimeToLive ) );
    } catch ( IException& e )
    {
        g_Error.Out( L_ALARM, e.GetErrorInfo() );
    }
    return StoreNode( pNode );
}

template <class IObject, class IKey>
IHashCacheNodeType * IHashCache<IObject, IKey>::SearchNode (const IKey &Key)
{
    int nPos = Hash( Key ) % m_nCacheBlocks;

    IHashCacheNodeType* pNode = m_apCacheTail[ nPos ];
    while ( pNode != NULL )
    {
        if ( pNode->m_Key == Key )
            break;
        else
            pNode = pNode->m_pHashPrevNode;
    }
    if ( pNode == NULL )    //Object not in cache
        return NULL;
    return pNode;
};

template <class IObject, class IKey>
int IHashCache<IObject, IKey>::Reap ()
{
    int nDeleted = 0;
    IDEBUG( g_Error.Out( L_DEBUG, "IHashCache: Begin to reap\n") );
    for ( int i=0; i < m_nNumToReap; i++ )
    {
        LockXX();
        if ( m_pAccessListHead == NULL )
        {
            UnLockXX(); //**
            break;
        }
        IKey Key = m_pAccessListHead->m_Key;
        UnLockXX();
        if ( Delete( Key ) )
            nDeleted++;
    }
    IDEBUG( g_Error.Out( L_DEBUG, "ICache: Finished reaping.\n" ) );
    return nDeleted;
}

template <class IObject, class IKey>
bool IHashCache<IObject, IKey>::IsFull ()
{
    return m_nCacheCount == m_nCacheSize || m_nUsedMem >= m_nMaxMem; 
};

template <class IObject, class IKey>
void IHashCache<IObject, IKey>::ReadLockNodeByKey ( const IKey &Key )
{
    int nPos = Hash( Key ) % m_nCacheBlocks;
    m_LockHash[ nPos ].ReadLock();
};

template <class IObject, class IKey>
void IHashCache<IObject, IKey>::WriteLockNodeByKey ( const IKey &Key )
{
    int nPos = Hash( Key ) % m_nCacheBlocks;
    m_LockHash[ nPos ].WriteLock();
};

template <class IObject, class IKey>
void IHashCache<IObject, IKey>::UnLockNodeByKey( const IKey &Key )
{
    int nPos = Hash( Key ) % m_nCacheBlocks;
    m_LockHash[ nPos ].Release();
};

template <class IObject, class IKey>
int IHashCache<IObject, IKey>::TryLockWhenCache ( const IKey &Key )
{
    int nPos = Hash( Key ) % m_nCacheBlocks;
    return m_LockHash[ nPos ].TryWriteLock();
};

template <class IObject, class IKey>
bool IHashCache<IObject, IKey>::AddNodeToContainer (IHashCacheNodeType *pNode)
{
    IHashCacheNodeType *pHashNode = (IHashCacheNodeType *)pNode;

    int nPos = Hash( pHashNode->m_Key )  % m_nCacheBlocks;

    if ( m_apCacheHead[ nPos ] == NULL )
    {
        m_apCacheHead[ nPos ] = pHashNode;
        m_apCacheTail[ nPos ] = pHashNode;
    } else
    {
        IHashCacheNodeType* pTail = m_apCacheTail[ nPos ];
        pHashNode->m_pHashPrevNode = pTail;
        //item->m_pHashNextNode = NULL;	//ommited
        pTail->m_pHashNextNode = pHashNode;
        m_apCacheTail[ nPos ] = pHashNode;
    }
    return true;
};

template <class IObject, class IKey>
bool IHashCache<IObject, IKey>::DelNodeFromContainer (IHashCacheNodeType *pNode)
{
    IHashCacheNodeType *pPrevNode = pNode->m_pHashPrevNode;
    IHashCacheNodeType *pNextNode = pNode->m_pHashNextNode;

    int nPos = Hash( pNode->m_Key )  % m_nCacheBlocks;

    if ( pPrevNode == NULL )
        m_apCacheHead[ nPos ] = pNextNode;
    else
        pPrevNode->m_pHashNextNode = pNextNode;

    if ( pNextNode == NULL )
        m_apCacheTail[ nPos ] = pPrevNode;
    else
        pNextNode->m_pHashPrevNode = pPrevNode;
    IDEBUG( g_Error.Out( L_DEBUG, "IHashCache: delete node from container.\n") );
    return true;
};

template <class IObject, class IKey>
bool IHashCache<IObject, IKey>::AddNodeToXX (IHashCacheNodeType *pNode)
{
    if ( m_pAccessListHead == NULL )
    {
        m_pAccessListHead = pNode;
        m_pAccessListTail = pNode;
    } else
    {
        pNode->m_pAccessListPrevNode = m_pAccessListTail;
        //item->m_pAccessListNextNode = NULL;	//ommited
        m_pAccessListTail->m_pAccessListNextNode = pNode;
        m_pAccessListTail = pNode;
    }
    return true;
};

template <class IObject, class IKey>
bool IHashCache<IObject, IKey>::DelNodeFromXX (IHashCacheNodeType *pNode)
{   
    IHashCacheNodeType* pPrevNode = pNode->m_pAccessListPrevNode;
    IHashCacheNodeType* pNextNode = pNode->m_pAccessListNextNode;

    if ( pPrevNode == NULL )
        m_pAccessListHead = pNextNode;
    else
        pPrevNode->m_pAccessListNextNode = pNextNode;

    if ( pNextNode == NULL )
        m_pAccessListTail = pPrevNode;
    else
        pNextNode->m_pAccessListPrevNode = pPrevNode;
    IDEBUG( g_Error.Out( L_DEBUG, "IHashCache: delete node from XX\n") ); 
    return true;
};

template <class IObject, class IKey>
void IHashCache<IObject, IKey>::LockXX ()
{
    m_LockAccessList.Lock();
};

template <class IObject, class IKey>
void IHashCache<IObject, IKey>::UnLockXX ()
{
    m_LockAccessList.ReleaseLock();
};

template <class IObject, class IKey>
bool IHashCache<IObject, IKey>::AdjustNodeFromXX (IHashCacheNodeType *pNode)
{
    pNode->m_nHits++;
    //Change the LRU list?
    if ( (pNode->m_nHits % m_nAdjustRate) == 0 )
    {
        //Move this node to the end of the list
        LockXX();
        if ( m_pAccessListTail != pNode )
        {
            // Remove node
            IHashCacheNodeType* pPrevNode = pNode->m_pAccessListPrevNode;
            IHashCacheNodeType* pNextNode = pNode->m_pAccessListNextNode;
            if ( pPrevNode == NULL )
                m_pAccessListHead = pNextNode;
            else
                pPrevNode->m_pAccessListNextNode = pNextNode;
            pNextNode->m_pAccessListPrevNode = pPrevNode;

            //Append to tail
            m_pAccessListTail->m_pAccessListNextNode = pNode;
            pNode->m_pAccessListNextNode = NULL;
            pNode->m_pAccessListPrevNode = m_pAccessListTail;
            m_pAccessListTail = pNode;
        }
        UnLockXX();
    }
    return true;
};

template <class IObject, class IKey>
bool IHashCache<IObject, IKey>::TimeOutHandler (IHashCacheNodeType *pNode)
{
    time_t now=time(NULL);
    if ( pNode->m_nTimeOut!=-1 && pNode->m_nTimeOut<now ) //This object already timeouted, shouldn't be used
    {
        DeleteNode( pNode );
        IDEBUG( g_Error.Out( L_DEBUG, "ICache: Key Expired, it will be deleted.\n" ) );
        return true;
    }
    return false;
};

template <class IObject, class IKey>
void IHashCache<IObject, IKey>::LockStore()
{
    m_LockStore.Lock();
};

template <class IObject, class IKey>
void IHashCache<IObject, IKey>::UnLockStore()
{
    m_LockStore.ReleaseLock();
};

template <class IObject, class IKey>
void IHashCache<IObject, IKey>::TraverseContainer()
{
    int i;
    IHashCacheNodeType *pNode;
    g_Error.Out( L_ALARM, "-----Content of Cache------\n" );
    for (i=0; i<m_nCacheBlocks; i++)
    {
        m_LockHash[i].WriteLock();
        pNode = m_apCacheHead[ i ];
        while ( pNode != NULL )
        {
            OnTraverseContainer( pNode );
            pNode = pNode->m_pHashNextNode;
        }
        m_LockHash[i].Release();
    }   
    g_Error.Out( L_ALARM, "\nCache Count = %d , Max Cache Size = %d\n", m_nCacheCount, m_nCacheSize ) ;
    g_Error.Out( L_ALARM, "----------------------------\n" ) ;
}

template <class IObject, class IKey>
void IHashCache<IObject, IKey>::TraverseXX()
{
    LockXX();
    g_Error.Out( L_ALARM, "---------LRU List-------------\n" ) ;
    IHashCacheNodeType *pNode = m_pAccessListHead;
    while ( pNode != NULL )
    {
        OnTraverseXX( pNode );
        pNode = pNode->m_pAccessListNextNode;
    }
    g_Error.Out( L_ALARM, "------------------------------\n" );
    UnLockXX();
}

template <class IObject, class IKey>
IObject IHashCache<IObject,IKey>::Fetch (const IKey &Key)
{   
    IObject ResObj; 
    ReadLockNodeByKey( Key );   
    IHashCacheNodeType *pNode = SearchNode( Key );  
    if ( pNode == NULL )
    {
        UnLockNodeByKey( Key );     
        return ResObj;
    }
    bool NodeTimeOut = TimeOutHandler( pNode );
    if ( NodeTimeOut )
    {
        UnLockNodeByKey( Key );
        return ResObj;
    }
    OnFetchNode( pNode );
    pNode->SetLastAccessTime( time(NULL) );
    AdjustNodeFromXX( pNode );
    ResObj = pNode->GetObject();
    IDEBUG( g_Error.Out( L_DEBUG, "ICache: Fetched the node from cache.\n" ) );
    UnLockNodeByKey( Key );
    return ResObj;
}

template <class IObject, class IKey>
IObject IHashCache<IObject,IKey>::FetchAndCache(const IKey &Key)
{   
    IObject ResObj; 
    ReadLockNodeByKey( Key );  
    IHashCacheNodeType *pNode = SearchNode( Key );  
	if( pNode==NULL )
	{
		UnLockNodeByKey(Key);
		if( TryLockWhenCache(Key)!=0 )
		{
			ReadLockNodeByKey(Key);
			pNode = SearchNode(Key);
		}
	}
    if ( pNode==NULL )            //   Not Existed in the Cache
    {
        try
        {
            GetCacheObject(Key,ResObj);
        } 
		catch (IException e )
        {
			UnLockNodeByKey( Key );
            throw;
        } catch ( ... )
        {
            UnLockNodeByKey( Key );
            throw;
        }
        XNew( pNode , IHashCacheNodeType( ResObj, Key, 0, -1 ) );
        LockStore();
        if ( IsFull() )
        {
            for ( int i=0; i < m_nNumToReap; i++ )
            {
                LockXX();
                if ( m_pAccessListHead == NULL )
                {
                    UnLockXX(); //**
                    break;
                }
                IHashCacheNodeType *p = m_pAccessListHead;
                OnDeleteNode( p );
                m_nCacheCount--;
                m_nUsedMem -= p->m_nSize;
                DelNodeFromXX( p );
                UnLockXX();
                DelNodeFromContainer( p );
                delete p;
            }

            if ( IsFull( ) ) //it almost couldn't be full.
            {
                //Can't complete the reap operation, can't cache any more object
                UnLockStore();
                UnLockNodeByKey(Key);
                return ResObj;
            }
        }
        OnInsertNode( pNode );
        m_nCacheCount++;
        m_nUsedMem += pNode->GetSize();
        AddNodeToContainer( pNode );
        LockXX();
        AddNodeToXX( pNode );
        UnLockXX();
        //ResObj = pNode->GetObject();
        IDEBUG( g_Error.Out( L_DEBUG, "ICache: Store a new node to cache.\n" ) );
        UnLockStore();
    } else
    {
        OnFetchNode( pNode );
        pNode->SetLastAccessTime( time(NULL) );
        AdjustNodeFromXX( pNode );
        ResObj = pNode->GetObject();
        IDEBUG( g_Error.Out( L_DEBUG, "ICache: Fetched the node from cache.\n" ) );
    }
    UnLockNodeByKey( Key );
    return ResObj;
}

template <class IObject, class IKey>
bool IHashCache<IObject,IKey>::Delete (const IKey &Key)
{
    WriteLockNodeByKey( Key );
    IHashCacheNodeType *pNode = SearchNode( Key );
    if ( pNode == NULL )
    {
        UnLockNodeByKey( Key );
        return false;
    }
    DeleteNode( pNode );
    IDEBUG( g_Error.Out( L_DEBUG, "ICache: Delete a node from cache.\n" ) );
    UnLockNodeByKey( Key );
    return true;
}

template <class IObject, class IKey>
void IHashCache<IObject, IKey>::DeleteNode( IHashCacheNodeType* pNode )
{
    OnDeleteNode( pNode );      
    m_nCacheCount--;
    m_nUsedMem -= pNode->m_nSize;
    LockXX();
    DelNodeFromXX( pNode );
    UnLockXX();
    DelNodeFromContainer( pNode );
    delete pNode;
}


template <class IObject, class IKey>
bool IHashCache<IObject,IKey>::StoreNode (IHashCacheNodeType *pNode)
{
    IObject ResObj;
    LockStore();
    if ( IsFull() )
    {
        if ( Reap()<=0 ) //Only when the objects to be free are all be freed by other thread.
            if ( IsFull( ) ) //if reap()<=0 , it almost couldn't be full.
            {
                //Can't complete the reap operation, can't cache any more object
                Delete( pNode->GetKey() );
                UnLockStore();
                return false;
            }
    }
    WriteLockNodeByKey( pNode->GetKey() );
    IHashCacheNodeType *pOldNode = SearchNode( pNode->GetKey() );
    if ( pOldNode != NULL )
        DeleteNode( pOldNode );
    OnInsertNode( pNode );
    m_nCacheCount++;
    m_nUsedMem += pNode->GetSize();
    AddNodeToContainer( pNode );
    LockXX();
    AddNodeToXX( pNode );
    UnLockXX();
    //ResObj = pNode->GetObject();
    IDEBUG( g_Error.Out( L_DEBUG, "ICache: Store a new node to cache.\n" ) );
    UnLockNodeByKey( pNode->GetKey() );
    UnLockStore();
    return true;
}

template <class IObject, class IKey>
int IHashCache<IObject,IKey>::GetObjectCount ()
{
    return m_nCacheCount;
}

#endif
分享到:
评论

相关推荐

    oracle_buffer_cache深入分析

    而为了提高数据访问速度,Oracle 引入了一个重要的内存组件——Buffer Cache(数据高速缓存区)。Buffer Cache 的核心作用在于减少磁盘 I/O 操作,因为相较于磁盘访问,内存访问速度快得多。 **1.1 Buffer Cache ...

    基于共享Cache多核处理器的Hash连接优化.pdf

    总的来说,该研究为多核处理器上的数据库查询优化提供了一个有价值的视角,特别是在处理大数据连接操作时,优化Hash连接的性能对于提升系统整体性能有着显著的作用。通过理解并应用文中提到的多线程执行框架、Radix-...

    搜索引擎应用技术--cache技术

    具体来说,当搜索引擎处理网页时,会根据网页的内容生成一个唯一的Hash值。这个Hash值作为索引的一部分,用于快速定位和检索网页。Hash算法具有快速计算和唯一性的特点,即使对于庞大的数据集,也能迅速找到对应的...

    深入Buffer Cache 原理

    - `NXT_HASH` 和 `PRV_HASH`:分别指向同一HashChain List中的下一个和上一个块地址,构成双向链表结构。 - `NXT_REPL` 和 `PRV_REPL`:分别指向LRU List中的下一个和上一个块地址,用于维护LRU链表。 - `TCH`:表示...

    hash-cache:简单,一致的磁盘缓存

    在第一个字节流出ReadStream之前,它将每个请求合并为一个。 要乐观。 不要检查缓存,然后从中获取内容。 尝试从中获取信息,如果我们遇到ENOENT ,请后退。 面对并发时保持正确。 我们竭尽全力确保流程相互等待...

    library_cache内存详解

    Library cache的管理由Library Cache Manager负责,它是Oracle内存管理器——KGH Heap Manager的一个客户端。Heap Manager负责分配和回收内存,对于shared pool,内存是预分配的,当进程需要内存时,Heap Manager...

    Cmake编译生成的dll文件缺少libopencv-world450.dll和opencv-videoio-ffmpeg-64

    #match_hash_in_cmake_cache "OCV_DOWNLOAD_ADE_HASH_3rdparty_ade_v0_1_2d_zip" #match_hash_in_cmake_cache "OCV_DOWNLOAD_FFMPEG_HASH_3rdparty_ffmpeg_opencv_videoio_ffmpeg_dll" #do_copy "opencv_videoio_...

    flashcache架构详解

    FlashCache的缓存结构基于集合相联式哈希(Set Associative Hash),它采用固定大小的桶(Bucket)集合,并通过线性探测法在一个桶内查找空位。默认情况下,FlashCache是512路集合相联式,也就是说每个桶可以关联...

    springboot 使用spring cache缓存 和 使用fastjson配置redis系列化

    在应用中启用Spring Cache,我们需要创建一个配置类,该类使用`@EnableCaching`注解开启缓存功能。同时,为了处理缓存中的对象序列化问题,我们使用Fastjson替换默认的JDK序列化。这通常涉及到创建一个自定义的`...

    redis-cluster和spring集成,基于cache注解

    综上所述,"redis-cluster和spring集成,基于cache注解" 的项目是一个使用 Spring Cache 集成 Redis 集群的实例,旨在通过注解的方式简化缓存管理,提高应用性能。开发者可以通过导入提供的项目,快速了解和实践这一...

    深入学习Buffer cache

    4. **Cache Buffer Chain Latch**:每个哈希桶都有一个缓存缓冲区链路锁,用于控制对Hash Chain的并发访问。当多个并发事务尝试访问同一数据块时,这些锁确保了数据的一致性和完整性。 5. **_db_block_hash_buckets...

    .cache.rar

    在这一过程中,CMake会将配置信息、依赖关系以及编译选项等数据存储在一个或多个.cache文件中。以题目中给出的例子“5de6044cad9398549e57bc46fc13908d-opencv_videoio_ffmpeg.dll”为例,这可能是一个针对特定模块...

    Hash计算器

    好用的Hash工具 abnormal_recovery: 0 boot: cd bootdisk: ide0 cfgstorage: local cores: 1 cpu: core2duo dir: 9882a70378e6 host: host-00900b24b834 ide0: local:vm-disk-1.qcow2,cache=directsync,preallocate=...

    redis-cache-mybatis

    本项目"redis-cache-mybatis"正是为了实现这一目的,提供了一个可以直接使用的Redis缓存解决方案。 在MyBatis中,Redis缓存主要涉及以下几个核心概念: 1. **配置Redis**:首先,我们需要在应用的配置文件中添加...

    cache buffers chain形成原因分析

    当一个进程需要对数据块进行操作时,它必须首先获取相应的`cache buffers chains latch`。例如,在执行一个逻辑读取操作时,不仅会消耗CPU时间,还需要获取一个`latch`锁。这意味着每次逻辑读操作都会引发一次`latch...

    C++实现一致性hash算法

    一致性hash应用于负载均衡算法,本实现由C++语言开发。 一致性hash算法提出了在动态变化的Cache环境中,判定哈希算法好坏的四个定义: 1、平衡性(Balance)2、单调性(Monotonicity) 3、分散性(Spread)4、负载(Load)

    Cache, Hash and Space-Efficient Bloom Filters-计算机科学

    Cache-, Hash- and Space-Efficient Bloom FiltersFelix Putze, Peter Sanders, Johannes Singler {putze,sanders,singler}@ira.uka.deFakultät für Informatik, Universität Karlsruhe, GermanyAbstract. A ...

Global site tag (gtag.js) - Google Analytics