diff -r 000000000000 -r 08ec8eefde2f persistentstorage/dbms/pcdbms/udbms/UD_CACHE.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/dbms/pcdbms/udbms/UD_CACHE.CPP Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,332 @@ +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// DBMS object cache +// +// + +#include "UD_STD.H" +#include "D32CACHE.H" +//#include + +NONSHARABLE_CLASS(RDbCache::CCache) : private CBase + { +public: + static CCache* OpenL( TInt aSize, TBool aUseTimer ); + void Close(); +// + void Flush(); + void Hold( CBase* aObject, TUint aMicroSeconds ); + void Release ( const CBase& aObject ); +private: + struct TEntry + { + TEntry* iNext; + TInt iDelta; + CBase* iObject; + }; + enum { ETimerPriority = -10 }; + enum { ETimerPeriod = 0x100000 }; // ~1.0s +private: + static inline TInt TlsHandle(); + CCache( TInt aSize ); + ~CCache(); +// + static CCache* NewL( TInt aSize, TBool aUseTimer ); + inline void Open(); + void Expire( TInt aElapsedTime ); + void Remove( TEntry*& aRef ); + void ExpireFirst(); + static void DoFlush( TAny* aPtr ); +private: + TInt iRef; +// CPeriodic* iTimer; + TTimeIntervalMicroSeconds32 iTickPeriod; + TUint iZeroTime; + TEntry* iCache; + TEntry* iFree; + TEntry iEntries[1]; // or maybe more + }; + +// Class CDbObjectCache + +//inline TInt RDbCache::CCache::TlsHandle() +//// use the address of a static function for the handle +// { return TInt( NewL ); } + +TAny* gCachePtr; + +RDbCache::CCache::CCache( TInt aSize ) +// +// Initialise the free entry list +// + { + TEntry* entry = iEntries; + while ( --aSize != 0 ) + { + entry[1].iNext = entry; + ++entry; + } + iFree = entry; + } + +RDbCache::CCache::~CCache() + { + __ASSERT( iRef < 0 ); +// empty the cache (destory the items now) + Expire( KMaxTInt ); + __ASSERT( iCache == 0 ); +// delete iTimer; + gCachePtr = NULL; + } + +const TInt KTickPeriod = 10000000; +const TTimeIntervalMicroSeconds32 gTickPeriod(KTickPeriod); +RDbCache::CCache* RDbCache::CCache::NewL( TInt aSize, TBool aUseTimer ) +// +// Construct a cache with aSize slots and one referee +// + { +//#warning !! RDbCache::CCache::NewL not implemented (uses UserHal/UserSvr) !! + CCache* cache = new( ELeave, sizeof( TEntry ) * ( aSize - 1 ) ) CCache( aSize ); // get the extra size for the cache entries, leaves on error + CleanupClosePushL( *cache ); + cache->iTickPeriod = gTickPeriod; + //User::LeaveIfError( UserHal::TickPeriod( cache->iTickPeriod ) ); + //User::LeaveIfError( UserSvr::DllSetTls( TlsHandle(), cache ) ); + gCachePtr = cache; +// if (aUseTimer) +// cache->iTimer = CPeriodic::NewL( ETimerPriority ); + CleanupStack::Pop(); + return cache; + } + +inline void RDbCache::CCache::Open() +// add a referee + { ++iRef; } + +void RDbCache::CCache::Close() +// +// remove a referee and delete as required +// + { + __ASSERT( iRef >= 0 ); + if ( --iRef < 0 ) + delete this; + } + +RDbCache::CCache* RDbCache::CCache::OpenL( TInt aSize, TBool aUseTimer ) +// +// Grab a reference to the cache, constructing it if required +// + { +// CCache* cache = ( CCache* )UserSvr::DllTls( TlsHandle() ); + CCache* cache = ( CCache* )gCachePtr; + if (!cache) + return NewL( aSize, aUseTimer ); + cache->Open(); + return cache; + } + +void RDbCache::CCache::Hold( CBase* aObject, TUint aMicroSeconds ) +// +// Hold aObject in the cache or destroy it +// + { + Flush(); // Destroy expired entries and re-assess Zero-time + TInt ticks = aMicroSeconds / TUint( iTickPeriod.Int() ); + TEntry* entry = iFree; + if ( entry == 0 ) + { // no free slots: check the first cache entry + __ASSERT( iCache ); + if ( iCache->iDelta > ticks ) + { // aObject expires first + delete aObject; + return; + } + ExpireFirst(); // remove the first entry and use it + entry = iFree; + } + iFree = entry->iNext; // move the free list pointer to the next entry + // + // find the insertion point in the cache delta-list + TEntry** pcache = &iCache; + TEntry* cache; + for ( ; ; ) + { + __ASSERT( ticks >= 0 ); + cache = *pcache; + if ( !cache ) + break; // add to end + TInt t = ticks - cache->iDelta; + if ( t < 0 ) + { // add to the list here + cache->iDelta = -t; // reduce the following delta + break; + } + ticks = t; // reduce the entry delta + pcache = &cache->iNext; + } + *pcache = entry; // set up the entry + entry->iDelta = ticks; + entry->iNext = cache; + entry->iObject = aObject; +// // kick the timer if we need to +// if ( iTimer && !iTimer->IsActive() ) +// iTimer->Start( ETimerPeriod, ETimerPeriod, TCallBack( ( TInt (*)(TAny*) )DoFlush, this ) ); + } + +void RDbCache::CCache::Remove( RDbCache::CCache::TEntry*& aRef ) +// +// Remove the entry at aRef from the cache +// + { + TEntry& entry = *aRef; + TEntry* next = entry.iNext; + entry.iNext = iFree; + iFree = &entry; + aRef = next; + if ( next ) + next->iDelta += entry.iDelta; +// else if ( iTimer ) // the cache is now empty, so stop the timer if we have one +// iTimer->Cancel(); + } + +void RDbCache::CCache::ExpireFirst() +// +// Expire the first entry in the cache +// + { + __ASSERT( iCache != 0 ); + // the ordering here is important. Removing the entry first allows the + // object d'tor to call Release() without causing re-entrancy problems. + CBase* object = iCache->iObject; + Remove( iCache ); + delete object; + } + +void RDbCache::CCache::Release( const CBase& aObject ) +// +// Remove the cache entry for aObject, if it is in the cache +// + { + TEntry** pcache = &iCache; + for ( ; ; ) + { + TEntry* entry = *pcache; + if ( !entry ) + return; + if ( entry->iObject == &aObject ) + { + Remove( *pcache ); + return; + } + pcache = &entry->iNext; + } + } + +void RDbCache::CCache::Expire( TInt aElapsedTime ) +// +// Destroy entries which expire with aElapsedTime +// + { + __ASSERT( aElapsedTime > 0 ); + if ( iCache && ( iCache->iDelta -= aElapsedTime ) < 0 ) + { + Open(); // This allows the cache to be owned by an object in the cache + do ExpireFirst(); + while ( iCache && iCache->iDelta < 0 ); + Close(); // The cache may be destroyed now + } + } + +void RDbCache::CCache::Flush() +// +// Check the execution clock and destroy any expired entries +// +// Care has to be taken to handle the 32-bit wraparound of the tick-count +// e.g. iZeroTime = 0xffffffffu, now = 0 +// + { + TUint now = User::TickCount(); + TUint elapsed = now - iZeroTime; + iZeroTime = now; + if ( elapsed ) + Expire( elapsed <= TUint( KMaxTInt ) ? elapsed : TUint( KMaxTInt ) ); + } + +void RDbCache::CCache::DoFlush( TAny* aPtr ) +// +// Callback for the timer +// + { + static_cast( aPtr )->Flush(); + } + + +// Class RDbCache + +TInt RDbCache::Open( TInt aSize, TBool aUseTimer ) +// +// Get a handle on the cache +// + { + __ASSERT( aSize > 0 ); + TRAPD( r, iCache = CCache::OpenL( aSize, aUseTimer ) ); + return r; + } + +void RDbCache::Close() +// +// Close this handle on the cache +// + { + CCache* cache = iCache; + if ( cache ) + { + iCache = 0; + cache->Close(); + } + } + +void RDbCache::Hold( CBase* aObject, TUint aMicroSeconds ) +// +// Hold aObject on the cache, if open +// We are now responsible for deleting the object +// + { + if ( iCache ) + iCache->Hold( aObject, aMicroSeconds ); + else + delete aObject; // no cache available + } + +void RDbCache::Release( const CBase& aObject ) const +// +// Retrieve aObject from the cache +// + { + if ( iCache ) + iCache->Release( aObject ); + } + +void RDbCache::Flush() +// +// Destroy any cached objects which have expired +// + { + if ( iCache ) + iCache->Flush(); + } + + +