os/persistentdata/persistentstorage/dbms/pcdbms/udbms/UD_CACHE.CPP
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // DBMS object cache
    15 // 
    16 //
    17 
    18 #include "UD_STD.H"
    19 #include "D32CACHE.H"
    20 //#include <e32svr.h>
    21 
    22 NONSHARABLE_CLASS(RDbCache::CCache) : private CBase
    23 	{
    24 public:
    25 	static CCache* OpenL( TInt aSize, TBool aUseTimer );
    26 	void Close();
    27 //
    28 	void Flush();
    29 	void Hold( CBase* aObject, TUint aMicroSeconds );
    30 	void Release ( const CBase& aObject );
    31 private:
    32 	struct TEntry
    33 		{
    34 		TEntry* iNext;
    35 		TInt iDelta;
    36 		CBase* iObject;
    37 		};
    38 	enum { ETimerPriority = -10 };
    39 	enum { ETimerPeriod = 0x100000 };	// ~1.0s
    40 private:
    41 	static inline TInt TlsHandle();
    42 	CCache( TInt aSize );
    43 	~CCache();
    44 //
    45 	static CCache* NewL( TInt aSize, TBool aUseTimer );
    46 	inline void Open();
    47 	void Expire( TInt aElapsedTime );
    48 	void Remove( TEntry*& aRef );
    49 	void ExpireFirst();
    50 	static void DoFlush( TAny* aPtr );
    51 private:
    52 	TInt iRef;
    53 //	CPeriodic* iTimer;
    54 	TTimeIntervalMicroSeconds32 iTickPeriod;
    55 	TUint iZeroTime;
    56 	TEntry* iCache;
    57 	TEntry* iFree;
    58 	TEntry iEntries[1];		// or maybe more
    59 	};
    60 
    61 // Class CDbObjectCache
    62 
    63 //inline TInt RDbCache::CCache::TlsHandle()
    64 //// use the address of a static function for the handle
    65 //	{ return TInt( NewL ); }
    66 
    67 TAny* gCachePtr;
    68 
    69 RDbCache::CCache::CCache( TInt aSize )
    70 //
    71 // Initialise the free entry list
    72 //
    73 	{
    74 	TEntry* entry = iEntries;
    75 	while ( --aSize != 0 )
    76 		{
    77 		entry[1].iNext = entry;
    78 		++entry;
    79 		}
    80 	iFree = entry;
    81 	}
    82 
    83 RDbCache::CCache::~CCache()
    84 	{
    85 	__ASSERT( iRef < 0 );
    86 // empty the cache (destory the items now)
    87 	Expire( KMaxTInt );
    88 	__ASSERT( iCache == 0 );
    89 //	delete iTimer;
    90 	gCachePtr = NULL;
    91 	}
    92 
    93 const TInt KTickPeriod = 10000000;
    94 const TTimeIntervalMicroSeconds32 gTickPeriod(KTickPeriod);
    95 RDbCache::CCache* RDbCache::CCache::NewL( TInt aSize, TBool aUseTimer )
    96 //
    97 // Construct a cache with aSize slots and one referee
    98 //
    99 	{
   100 //#warning !! RDbCache::CCache::NewL not implemented (uses UserHal/UserSvr) !!
   101 	CCache* cache = new( ELeave, sizeof( TEntry ) * ( aSize - 1 ) ) CCache( aSize );	// get the extra size for the cache entries, leaves on error
   102 	CleanupClosePushL( *cache );
   103 	cache->iTickPeriod = gTickPeriod;
   104 	//User::LeaveIfError( UserHal::TickPeriod( cache->iTickPeriod ) );
   105 	//User::LeaveIfError( UserSvr::DllSetTls( TlsHandle(), cache ) );
   106 	gCachePtr = cache;
   107 //	if (aUseTimer)
   108 //		cache->iTimer = CPeriodic::NewL( ETimerPriority );
   109 	CleanupStack::Pop();
   110 	return cache;
   111 	}
   112 
   113 inline void RDbCache::CCache::Open()
   114 // add a referee
   115 	{ ++iRef; }
   116 
   117 void RDbCache::CCache::Close()
   118 //
   119 // remove a referee and delete as required
   120 //
   121 	{
   122 	__ASSERT( iRef >= 0 );
   123 	if ( --iRef < 0 )
   124 		delete this;
   125 	}
   126 
   127 RDbCache::CCache* RDbCache::CCache::OpenL( TInt aSize, TBool aUseTimer )
   128 //
   129 // Grab a reference to the cache, constructing it if required
   130 //
   131 	{
   132 //	CCache* cache = ( CCache* )UserSvr::DllTls( TlsHandle() );
   133 	CCache* cache = ( CCache* )gCachePtr;
   134 	if (!cache)
   135 		return NewL( aSize, aUseTimer );
   136 	cache->Open();
   137 	return cache;
   138 	}
   139 
   140 void RDbCache::CCache::Hold( CBase* aObject, TUint aMicroSeconds )
   141 //
   142 // Hold aObject in the cache or destroy it
   143 //
   144 	{
   145 	Flush();		// Destroy expired entries and re-assess Zero-time
   146 	TInt ticks = aMicroSeconds / TUint( iTickPeriod.Int() );
   147 	TEntry* entry = iFree;
   148 	if ( entry == 0 )
   149 		{	// no free slots: check the first cache entry
   150 		__ASSERT( iCache );
   151 		if ( iCache->iDelta > ticks )
   152 			{				// aObject expires first
   153 			delete aObject;
   154 			return;
   155 			}
   156 		ExpireFirst();		// remove the first entry and use it
   157 		entry = iFree;
   158 		}
   159 	iFree = entry->iNext;	// move the free list pointer to the next entry
   160 	//
   161 	// find the insertion point in the cache delta-list
   162 	TEntry** pcache = &iCache;
   163 	TEntry* cache;
   164 	for ( ; ; )
   165 		{
   166 		__ASSERT( ticks >= 0 );
   167 		cache = *pcache;
   168 		if ( !cache )
   169 			break;				// add to end
   170 		TInt t = ticks - cache->iDelta;
   171 		if ( t < 0 )
   172 			{					// add to the list here
   173 			cache->iDelta = -t;	// reduce the following delta
   174 			break;
   175 			}
   176 		ticks = t;				// reduce the entry delta
   177 		pcache = &cache->iNext;
   178 		}
   179 	*pcache = entry;				// set up the entry
   180 	entry->iDelta = ticks;
   181 	entry->iNext = cache;
   182 	entry->iObject = aObject;
   183 //	// kick the timer if we need to
   184 //	if ( iTimer && !iTimer->IsActive() )
   185 //		iTimer->Start( ETimerPeriod, ETimerPeriod, TCallBack( ( TInt (*)(TAny*) )DoFlush, this ) );
   186 	}
   187 
   188 void RDbCache::CCache::Remove( RDbCache::CCache::TEntry*& aRef )
   189 //
   190 // Remove the entry at aRef from the cache
   191 //
   192 	{
   193 	TEntry& entry = *aRef;
   194 	TEntry* next = entry.iNext;
   195 	entry.iNext = iFree;
   196 	iFree = &entry;
   197 	aRef = next;
   198 	if ( next )
   199 		next->iDelta += entry.iDelta;
   200 //	else if ( iTimer )	// the cache is now empty, so stop the timer if we have one
   201 //		iTimer->Cancel();
   202 	}
   203 
   204 void RDbCache::CCache::ExpireFirst()
   205 //
   206 // Expire the first entry in the cache
   207 //
   208 	{
   209 	__ASSERT( iCache != 0 );
   210 	// the ordering here is important. Removing the entry first allows the
   211 	// object d'tor to call Release() without causing re-entrancy problems.
   212 	CBase* object = iCache->iObject;
   213 	Remove( iCache );
   214 	delete object;
   215 	}
   216 
   217 void RDbCache::CCache::Release( const CBase& aObject )
   218 //
   219 // Remove the cache entry for aObject, if it is in the cache
   220 //
   221 	{
   222 	TEntry** pcache = &iCache;
   223 	for ( ; ; )
   224 		{
   225 		TEntry* entry = *pcache;
   226 		if ( !entry )
   227 			return;
   228 		if ( entry->iObject == &aObject )
   229 			{
   230 			Remove( *pcache );
   231 			return;
   232 			}
   233 		pcache = &entry->iNext;
   234 		}
   235 	}
   236 
   237 void RDbCache::CCache::Expire( TInt aElapsedTime )
   238 //
   239 // Destroy entries which expire with aElapsedTime
   240 //
   241 	{
   242 	__ASSERT( aElapsedTime > 0 );
   243 	if ( iCache && ( iCache->iDelta -= aElapsedTime ) < 0 )
   244 		{
   245 		Open();		// This allows the cache to be owned by an object in the cache
   246 		do ExpireFirst();
   247 			while ( iCache && iCache->iDelta < 0 );
   248 		Close();	// The cache may be destroyed now
   249 		}
   250 	}
   251 
   252 void RDbCache::CCache::Flush()
   253 //
   254 // Check the execution clock and destroy any expired entries
   255 //
   256 // Care has to be taken to handle the 32-bit wraparound of the tick-count
   257 // e.g. iZeroTime = 0xffffffffu, now = 0
   258 //
   259 	{
   260 	TUint now = User::TickCount();
   261 	TUint elapsed = now - iZeroTime;
   262 	iZeroTime = now;
   263 	if ( elapsed )
   264 		Expire( elapsed <= TUint( KMaxTInt ) ? elapsed : TUint( KMaxTInt ) );
   265 	}
   266 
   267 void RDbCache::CCache::DoFlush( TAny* aPtr )
   268 //
   269 // Callback for the timer
   270 //
   271 	{
   272 	static_cast<CCache*>( aPtr )->Flush();
   273 	}
   274 
   275 
   276 // Class RDbCache
   277 
   278 TInt RDbCache::Open( TInt aSize, TBool aUseTimer )
   279 //
   280 // Get a handle on the cache
   281 //
   282 	{
   283 	__ASSERT( aSize > 0 );
   284 	TRAPD( r, iCache = CCache::OpenL( aSize, aUseTimer ) );
   285 	return r;
   286 	}
   287 
   288 void RDbCache::Close()
   289 //
   290 // Close this handle on the cache
   291 //
   292 	{
   293 	CCache* cache = iCache;
   294 	if ( cache )
   295 		{
   296 		iCache = 0;
   297 		cache->Close();
   298 		}
   299 	}
   300 
   301 void RDbCache::Hold( CBase* aObject, TUint aMicroSeconds )
   302 //
   303 // Hold aObject on the cache, if open
   304 // We are now responsible for deleting the object
   305 //
   306 	{
   307 	if ( iCache )
   308 		iCache->Hold( aObject, aMicroSeconds );
   309 	else
   310 		delete aObject;	// no cache available
   311 	}
   312 
   313 void RDbCache::Release( const CBase& aObject ) const
   314 //
   315 // Retrieve aObject from the cache
   316 //
   317 	{
   318 	if ( iCache )
   319 		iCache->Release( aObject );
   320 	}
   321 
   322 void RDbCache::Flush()
   323 //
   324 // Destroy any cached objects which have expired
   325 //
   326 	{
   327 	if ( iCache )
   328 		iCache->Flush();
   329 	}
   330 
   331 
   332