--- /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 <e32svr.h>
+
+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<CCache*>( 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();
+ }
+
+
+