1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/dbms/pcdbms/udbms/UD_CACHE.CPP Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,332 @@
1.4 +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// DBMS object cache
1.18 +//
1.19 +//
1.20 +
1.21 +#include "UD_STD.H"
1.22 +#include "D32CACHE.H"
1.23 +//#include <e32svr.h>
1.24 +
1.25 +NONSHARABLE_CLASS(RDbCache::CCache) : private CBase
1.26 + {
1.27 +public:
1.28 + static CCache* OpenL( TInt aSize, TBool aUseTimer );
1.29 + void Close();
1.30 +//
1.31 + void Flush();
1.32 + void Hold( CBase* aObject, TUint aMicroSeconds );
1.33 + void Release ( const CBase& aObject );
1.34 +private:
1.35 + struct TEntry
1.36 + {
1.37 + TEntry* iNext;
1.38 + TInt iDelta;
1.39 + CBase* iObject;
1.40 + };
1.41 + enum { ETimerPriority = -10 };
1.42 + enum { ETimerPeriod = 0x100000 }; // ~1.0s
1.43 +private:
1.44 + static inline TInt TlsHandle();
1.45 + CCache( TInt aSize );
1.46 + ~CCache();
1.47 +//
1.48 + static CCache* NewL( TInt aSize, TBool aUseTimer );
1.49 + inline void Open();
1.50 + void Expire( TInt aElapsedTime );
1.51 + void Remove( TEntry*& aRef );
1.52 + void ExpireFirst();
1.53 + static void DoFlush( TAny* aPtr );
1.54 +private:
1.55 + TInt iRef;
1.56 +// CPeriodic* iTimer;
1.57 + TTimeIntervalMicroSeconds32 iTickPeriod;
1.58 + TUint iZeroTime;
1.59 + TEntry* iCache;
1.60 + TEntry* iFree;
1.61 + TEntry iEntries[1]; // or maybe more
1.62 + };
1.63 +
1.64 +// Class CDbObjectCache
1.65 +
1.66 +//inline TInt RDbCache::CCache::TlsHandle()
1.67 +//// use the address of a static function for the handle
1.68 +// { return TInt( NewL ); }
1.69 +
1.70 +TAny* gCachePtr;
1.71 +
1.72 +RDbCache::CCache::CCache( TInt aSize )
1.73 +//
1.74 +// Initialise the free entry list
1.75 +//
1.76 + {
1.77 + TEntry* entry = iEntries;
1.78 + while ( --aSize != 0 )
1.79 + {
1.80 + entry[1].iNext = entry;
1.81 + ++entry;
1.82 + }
1.83 + iFree = entry;
1.84 + }
1.85 +
1.86 +RDbCache::CCache::~CCache()
1.87 + {
1.88 + __ASSERT( iRef < 0 );
1.89 +// empty the cache (destory the items now)
1.90 + Expire( KMaxTInt );
1.91 + __ASSERT( iCache == 0 );
1.92 +// delete iTimer;
1.93 + gCachePtr = NULL;
1.94 + }
1.95 +
1.96 +const TInt KTickPeriod = 10000000;
1.97 +const TTimeIntervalMicroSeconds32 gTickPeriod(KTickPeriod);
1.98 +RDbCache::CCache* RDbCache::CCache::NewL( TInt aSize, TBool aUseTimer )
1.99 +//
1.100 +// Construct a cache with aSize slots and one referee
1.101 +//
1.102 + {
1.103 +//#warning !! RDbCache::CCache::NewL not implemented (uses UserHal/UserSvr) !!
1.104 + CCache* cache = new( ELeave, sizeof( TEntry ) * ( aSize - 1 ) ) CCache( aSize ); // get the extra size for the cache entries, leaves on error
1.105 + CleanupClosePushL( *cache );
1.106 + cache->iTickPeriod = gTickPeriod;
1.107 + //User::LeaveIfError( UserHal::TickPeriod( cache->iTickPeriod ) );
1.108 + //User::LeaveIfError( UserSvr::DllSetTls( TlsHandle(), cache ) );
1.109 + gCachePtr = cache;
1.110 +// if (aUseTimer)
1.111 +// cache->iTimer = CPeriodic::NewL( ETimerPriority );
1.112 + CleanupStack::Pop();
1.113 + return cache;
1.114 + }
1.115 +
1.116 +inline void RDbCache::CCache::Open()
1.117 +// add a referee
1.118 + { ++iRef; }
1.119 +
1.120 +void RDbCache::CCache::Close()
1.121 +//
1.122 +// remove a referee and delete as required
1.123 +//
1.124 + {
1.125 + __ASSERT( iRef >= 0 );
1.126 + if ( --iRef < 0 )
1.127 + delete this;
1.128 + }
1.129 +
1.130 +RDbCache::CCache* RDbCache::CCache::OpenL( TInt aSize, TBool aUseTimer )
1.131 +//
1.132 +// Grab a reference to the cache, constructing it if required
1.133 +//
1.134 + {
1.135 +// CCache* cache = ( CCache* )UserSvr::DllTls( TlsHandle() );
1.136 + CCache* cache = ( CCache* )gCachePtr;
1.137 + if (!cache)
1.138 + return NewL( aSize, aUseTimer );
1.139 + cache->Open();
1.140 + return cache;
1.141 + }
1.142 +
1.143 +void RDbCache::CCache::Hold( CBase* aObject, TUint aMicroSeconds )
1.144 +//
1.145 +// Hold aObject in the cache or destroy it
1.146 +//
1.147 + {
1.148 + Flush(); // Destroy expired entries and re-assess Zero-time
1.149 + TInt ticks = aMicroSeconds / TUint( iTickPeriod.Int() );
1.150 + TEntry* entry = iFree;
1.151 + if ( entry == 0 )
1.152 + { // no free slots: check the first cache entry
1.153 + __ASSERT( iCache );
1.154 + if ( iCache->iDelta > ticks )
1.155 + { // aObject expires first
1.156 + delete aObject;
1.157 + return;
1.158 + }
1.159 + ExpireFirst(); // remove the first entry and use it
1.160 + entry = iFree;
1.161 + }
1.162 + iFree = entry->iNext; // move the free list pointer to the next entry
1.163 + //
1.164 + // find the insertion point in the cache delta-list
1.165 + TEntry** pcache = &iCache;
1.166 + TEntry* cache;
1.167 + for ( ; ; )
1.168 + {
1.169 + __ASSERT( ticks >= 0 );
1.170 + cache = *pcache;
1.171 + if ( !cache )
1.172 + break; // add to end
1.173 + TInt t = ticks - cache->iDelta;
1.174 + if ( t < 0 )
1.175 + { // add to the list here
1.176 + cache->iDelta = -t; // reduce the following delta
1.177 + break;
1.178 + }
1.179 + ticks = t; // reduce the entry delta
1.180 + pcache = &cache->iNext;
1.181 + }
1.182 + *pcache = entry; // set up the entry
1.183 + entry->iDelta = ticks;
1.184 + entry->iNext = cache;
1.185 + entry->iObject = aObject;
1.186 +// // kick the timer if we need to
1.187 +// if ( iTimer && !iTimer->IsActive() )
1.188 +// iTimer->Start( ETimerPeriod, ETimerPeriod, TCallBack( ( TInt (*)(TAny*) )DoFlush, this ) );
1.189 + }
1.190 +
1.191 +void RDbCache::CCache::Remove( RDbCache::CCache::TEntry*& aRef )
1.192 +//
1.193 +// Remove the entry at aRef from the cache
1.194 +//
1.195 + {
1.196 + TEntry& entry = *aRef;
1.197 + TEntry* next = entry.iNext;
1.198 + entry.iNext = iFree;
1.199 + iFree = &entry;
1.200 + aRef = next;
1.201 + if ( next )
1.202 + next->iDelta += entry.iDelta;
1.203 +// else if ( iTimer ) // the cache is now empty, so stop the timer if we have one
1.204 +// iTimer->Cancel();
1.205 + }
1.206 +
1.207 +void RDbCache::CCache::ExpireFirst()
1.208 +//
1.209 +// Expire the first entry in the cache
1.210 +//
1.211 + {
1.212 + __ASSERT( iCache != 0 );
1.213 + // the ordering here is important. Removing the entry first allows the
1.214 + // object d'tor to call Release() without causing re-entrancy problems.
1.215 + CBase* object = iCache->iObject;
1.216 + Remove( iCache );
1.217 + delete object;
1.218 + }
1.219 +
1.220 +void RDbCache::CCache::Release( const CBase& aObject )
1.221 +//
1.222 +// Remove the cache entry for aObject, if it is in the cache
1.223 +//
1.224 + {
1.225 + TEntry** pcache = &iCache;
1.226 + for ( ; ; )
1.227 + {
1.228 + TEntry* entry = *pcache;
1.229 + if ( !entry )
1.230 + return;
1.231 + if ( entry->iObject == &aObject )
1.232 + {
1.233 + Remove( *pcache );
1.234 + return;
1.235 + }
1.236 + pcache = &entry->iNext;
1.237 + }
1.238 + }
1.239 +
1.240 +void RDbCache::CCache::Expire( TInt aElapsedTime )
1.241 +//
1.242 +// Destroy entries which expire with aElapsedTime
1.243 +//
1.244 + {
1.245 + __ASSERT( aElapsedTime > 0 );
1.246 + if ( iCache && ( iCache->iDelta -= aElapsedTime ) < 0 )
1.247 + {
1.248 + Open(); // This allows the cache to be owned by an object in the cache
1.249 + do ExpireFirst();
1.250 + while ( iCache && iCache->iDelta < 0 );
1.251 + Close(); // The cache may be destroyed now
1.252 + }
1.253 + }
1.254 +
1.255 +void RDbCache::CCache::Flush()
1.256 +//
1.257 +// Check the execution clock and destroy any expired entries
1.258 +//
1.259 +// Care has to be taken to handle the 32-bit wraparound of the tick-count
1.260 +// e.g. iZeroTime = 0xffffffffu, now = 0
1.261 +//
1.262 + {
1.263 + TUint now = User::TickCount();
1.264 + TUint elapsed = now - iZeroTime;
1.265 + iZeroTime = now;
1.266 + if ( elapsed )
1.267 + Expire( elapsed <= TUint( KMaxTInt ) ? elapsed : TUint( KMaxTInt ) );
1.268 + }
1.269 +
1.270 +void RDbCache::CCache::DoFlush( TAny* aPtr )
1.271 +//
1.272 +// Callback for the timer
1.273 +//
1.274 + {
1.275 + static_cast<CCache*>( aPtr )->Flush();
1.276 + }
1.277 +
1.278 +
1.279 +// Class RDbCache
1.280 +
1.281 +TInt RDbCache::Open( TInt aSize, TBool aUseTimer )
1.282 +//
1.283 +// Get a handle on the cache
1.284 +//
1.285 + {
1.286 + __ASSERT( aSize > 0 );
1.287 + TRAPD( r, iCache = CCache::OpenL( aSize, aUseTimer ) );
1.288 + return r;
1.289 + }
1.290 +
1.291 +void RDbCache::Close()
1.292 +//
1.293 +// Close this handle on the cache
1.294 +//
1.295 + {
1.296 + CCache* cache = iCache;
1.297 + if ( cache )
1.298 + {
1.299 + iCache = 0;
1.300 + cache->Close();
1.301 + }
1.302 + }
1.303 +
1.304 +void RDbCache::Hold( CBase* aObject, TUint aMicroSeconds )
1.305 +//
1.306 +// Hold aObject on the cache, if open
1.307 +// We are now responsible for deleting the object
1.308 +//
1.309 + {
1.310 + if ( iCache )
1.311 + iCache->Hold( aObject, aMicroSeconds );
1.312 + else
1.313 + delete aObject; // no cache available
1.314 + }
1.315 +
1.316 +void RDbCache::Release( const CBase& aObject ) const
1.317 +//
1.318 +// Retrieve aObject from the cache
1.319 +//
1.320 + {
1.321 + if ( iCache )
1.322 + iCache->Release( aObject );
1.323 + }
1.324 +
1.325 +void RDbCache::Flush()
1.326 +//
1.327 +// Destroy any cached objects which have expired
1.328 +//
1.329 + {
1.330 + if ( iCache )
1.331 + iCache->Flush();
1.332 + }
1.333 +
1.334 +
1.335 +