lowlevellibsandfws/pluginfw/Framework/frame/resolvercache.cpp
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 // Copyright (c) 2008-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 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @internalComponent
       
    19 */
       
    20 
       
    21 #include <e32def.h>
       
    22 #include <e32cmn.h>
       
    23 #include <hal.h>
       
    24 #include "EComDebug.h"
       
    25 #include "ImplementationInformation.h"  // CompareTUidValues
       
    26 #include "callback.h"
       
    27 #include "resolvercache.h"
       
    28 #include "EComPatchDataConstantv2.h"
       
    29 
       
    30 const TInt KCacheQueueGranularity = 4;
       
    31 
       
    32 //
       
    33 // TCounterTicks class
       
    34 //
       
    35 inline TCounterTicks::TCounterTicks(TUint aTicks)
       
    36 	: iTicks(aTicks)
       
    37 	{
       
    38 	}
       
    39 
       
    40 /** This substraction calculate elapsed ticks: aEndTick - this */
       
    41 inline
       
    42 TUint TCounterTicks::ElapsedSinceThis(TUint aEndTick) const
       
    43 	{
       
    44 	TUint diff;
       
    45 	if (aEndTick < iTicks) // wrap around occurred
       
    46 		{
       
    47 		diff = KMaxTUint - iTicks + aEndTick + 1;
       
    48 		}
       
    49 	else
       
    50 		{
       
    51 		diff = aEndTick - iTicks;
       
    52 		}
       
    53 	return diff;
       
    54 	}
       
    55 
       
    56 /** default constructor which initializes all member data to 0. */
       
    57 RResolverCacheEntry::RResolverCacheEntry()
       
    58 	: iLastUse( TCounterTicks(0) ), iLruRank(0), iResolverUid(KNullUid),
       
    59 	iNewLFuncPtr(NULL), iFlags(EEntryFlagsNone)
       
    60 	{
       
    61 	iLibrary.SetHandle(KNullHandle);
       
    62 	}
       
    63 
       
    64 /** construct RResolverCacheEntry with specific data
       
    65 @param aResolverUid TUid of the resolver.
       
    66 @param aLib RLibrary with handle open on the resolver DLL.
       
    67 @param aNewL Function ptr to instantiate the resolver.
       
    68 @param aFlags Special conditions about the cache entry.
       
    69 */
       
    70 RResolverCacheEntry::RResolverCacheEntry(const TUid aResolverUid,
       
    71 										RLibrary aLib,
       
    72 										TProxyNewLPtr aNewL,
       
    73 										TUint32 aFlags)
       
    74 	: iLastUse( TCounterTicks(0) ), iLruRank(0), iResolverUid(aResolverUid),
       
    75 	iNewLFuncPtr(aNewL), iFlags(aFlags)
       
    76 	{
       
    77 	iLibrary.SetHandle(aLib.Handle());
       
    78 	}
       
    79 
       
    80 /** unallocate resources owned by the RResolverCacheEntry object */
       
    81 void RResolverCacheEntry::Close()
       
    82 	{
       
    83 	iLibrary.Close();
       
    84 	}
       
    85 
       
    86 /** This method compares two RResolverCacheEntry objects.
       
    87 @param aEntry1 first RResolverCacheEntry object.
       
    88 @param aEntry2 second RResolverCacheEntry object.
       
    89 @return 0 means the two objects are equal.
       
    90         positive value means first object is greater than the second.
       
    91 		negative vlaue means second object is greater than the first.
       
    92 */
       
    93 TInt RResolverCacheEntry::CompareUid(const RResolverCacheEntry& aEntry1,
       
    94 								     const RResolverCacheEntry& aEntry2)
       
    95 	{
       
    96 	return CompareTUidValues(aEntry1.iResolverUid.iUid,
       
    97 							 aEntry2.iResolverUid.iUid);
       
    98 	}
       
    99 
       
   100 /** Compare the age of two cache entries.
       
   101 @param aOther The RResolverCacheEntry to compare with.
       
   102 @param aCurrTick The current system tick. It simplifies handling
       
   103 	of system tick wrap around to zero.
       
   104 @return ETrue means "this" object is older than aOther.
       
   105 	EFalse means aOther is older than "this".
       
   106 */
       
   107 TBool RResolverCacheEntry::ThisIsOlder(const RResolverCacheEntry& aOther,
       
   108 										TUint aCurrTick) const
       
   109 	{
       
   110 	if (iLastUse.iTicks == aOther.iLastUse.iTicks)
       
   111 		{
       
   112 		return iLruRank < aOther.iLruRank;
       
   113 		}
       
   114 
       
   115 	// Because of counter wrap around, it is not safe to directly
       
   116 	// compare the two ticks. Drag in the current system tick.
       
   117 	return iLastUse.ElapsedSinceThis(aCurrTick) >
       
   118 			aOther.iLastUse.ElapsedSinceThis(aCurrTick);
       
   119 	}
       
   120 
       
   121 //=================================
       
   122 // CCustomResolverCache class
       
   123 //=================================
       
   124 
       
   125 /** CCustomResolverCache constructor
       
   126 @param aCacheSize Maximum number of entries allowed to cache.
       
   127 */
       
   128 CCustomResolverCache::CCustomResolverCache(TUint32 aCacheSize)
       
   129 	: CTimer(CActive::EPriorityStandard),
       
   130 	iResolvers(KCacheQueueGranularity), 
       
   131 	iMaxCacheSize(aCacheSize)
       
   132 	{
       
   133 	}
       
   134 
       
   135 /** static factory method to instantiate CCustomResolverCache
       
   136 @param aCacheSize Maximum number of entries allowed to cache.
       
   137 @param aCacheTimeout Cache timeout in microseconds.
       
   138 @leave Any of the system wide error codes.
       
   139 */
       
   140 CCustomResolverCache* CCustomResolverCache::NewL(TUint32 aCacheSize, TUint32 aCacheTimeout)
       
   141 	{
       
   142 	CCustomResolverCache* self = new (ELeave) CCustomResolverCache(aCacheSize);
       
   143 	CleanupStack::PushL(self);
       
   144 	self->ConstructL(aCacheTimeout);
       
   145 	CleanupStack::Pop(self);
       
   146 	return self;
       
   147 	}
       
   148 
       
   149 /** Standard two phase construction to complete construction of
       
   150 the CCustomResolverCache object.
       
   151 @param aCacheTimeout Cache timeout in microseconds.
       
   152 @leave Any of the system wide error codes.
       
   153 */
       
   154 void CCustomResolverCache::ConstructL(TUint32 aCacheTimeout)
       
   155 	{
       
   156 	User::LeaveIfError(HAL::Get(HALData::ESystemTickPeriod,
       
   157 								iSystemTickPeriod));
       
   158 	iEntryTimeToLive = (aCacheTimeout + iSystemTickPeriod - 1) / iSystemTickPeriod;
       
   159 
       
   160 	CTimer::ConstructL();
       
   161 	CActiveScheduler::Add(this);
       
   162 	}
       
   163 
       
   164 /** CCustomResolverCache destructor */
       
   165 CCustomResolverCache::~CCustomResolverCache()
       
   166 	{
       
   167 	Cancel();
       
   168 	for (TInt i = iResolvers.Count() - 1; i >= 0; i--)
       
   169 		{
       
   170 		iResolvers[i].Close();
       
   171 		}
       
   172 	iResolvers.Reset();
       
   173 	}
       
   174 
       
   175 /** Implement the CActive RunL pure virtual */
       
   176 void CCustomResolverCache::RunL()
       
   177 	{
       
   178 	TUint currTickCount = User::TickCount();
       
   179 	TUint lruAge = 0;
       
   180 
       
   181 	for (TInt i = iResolvers.Count() - 1; i >= 0; i--)
       
   182 		{
       
   183 		RResolverCacheEntry& resolverEntry = iResolvers[i];
       
   184 		TUint age = resolverEntry.iLastUse.ElapsedSinceThis(currTickCount);
       
   185 		if (age >= iEntryTimeToLive)
       
   186 			{
       
   187 			resolverEntry.Close();
       
   188 			iResolvers.Remove(i);
       
   189 			}
       
   190 		else if (age > lruAge)
       
   191 			{
       
   192 			lruAge = age;
       
   193 			}
       
   194 		}
       
   195 
       
   196 	if (iResolvers.Count() > 0)
       
   197 		{
       
   198 		After( iSystemTickPeriod * (iEntryTimeToLive - lruAge + 1) );
       
   199 		}
       
   200 
       
   201 #ifdef __ECOMSERVER_TESTING__
       
   202 	// In unit testing notify test bed that cache timer has fired.
       
   203 	iTimerExpireCB.CallBack(0, NULL);
       
   204 #endif
       
   205 	}
       
   206 
       
   207 /** Search of a resolver UID in cache
       
   208 @param aResolverUid the resolver to search for.
       
   209 @return If find is successful, index of the resolver in RArray of cached resolvers.
       
   210 		Return KErrNotFound if resolver is not in cache.
       
   211 */
       
   212 TInt CCustomResolverCache::FindResolver(const TUid aResolverUid) const
       
   213 	{
       
   214 	RResolverCacheEntry trgt;
       
   215 	trgt.iResolverUid = aResolverUid;
       
   216 	TLinearOrder<RResolverCacheEntry> comparator(RResolverCacheEntry::CompareUid);
       
   217 	return iResolvers.FindInOrder(trgt, comparator);
       
   218 	}
       
   219 
       
   220 /** Add a resolver library to cache 
       
   221 @param aResolverUid Implementation UID of the resolver.
       
   222 @param aLib	The RLibrary object which has the resolver loaded. The handle
       
   223 	of the RLibrary is owned by the cache if call is successful.
       
   224 @param aNewL value for the iNewLFuncPtr member data of RResolverCacheEntry.
       
   225 @param aFlags value for the iFlags member data of RResolverCacheEntry.
       
   226 @return KErrNone if the data is added to cache.
       
   227 	KErrNoMemory if fail to insert the data in RArray.
       
   228 */
       
   229 TInt CCustomResolverCache::CacheResolver(const TUid aResolverUid,
       
   230 										  RLibrary aLib,
       
   231 										  TProxyNewLPtr aNewL,
       
   232 										  TUint32 aFlags)
       
   233 	{
       
   234 	if (iResolvers.Count() == iMaxCacheSize)
       
   235 		{
       
   236 		EvictLeastRecentlyUsed();
       
   237 		}
       
   238 
       
   239 	RResolverCacheEntry entry(aResolverUid, aLib, aNewL, aFlags);
       
   240 	SetLastUseTime(entry);
       
   241 
       
   242 #ifdef ECOM_TRACE
       
   243 	__ECOM_TRACE2("ECOM: adding custom resolver 0x%X to cache. New queue size will be %d.\n", aResolverUid.iUid, 1 + iResolvers.Count());
       
   244 #endif
       
   245 
       
   246 	TLinearOrder<RResolverCacheEntry> comparator(RResolverCacheEntry::CompareUid);
       
   247 	TInt err = iResolvers.InsertInOrder(entry, comparator);
       
   248 
       
   249 	// if cache was empty before need to start timer
       
   250 	if (err == KErrNone && ! IsActive())
       
   251 		{
       
   252 		After( iSystemTickPeriod * (iEntryTimeToLive + 1) );
       
   253 		}
       
   254 	return err;
       
   255 	}
       
   256 
       
   257 /** Check if both queue size and cache timeout are non zero  */
       
   258 TBool CCustomResolverCache::CachingEnabled() const
       
   259 	{
       
   260 	return (iMaxCacheSize && iEntryTimeToLive);
       
   261 	}
       
   262 
       
   263 /** Remove a cached entry
       
   264 @param aIndex position of entry in the array.
       
   265 */
       
   266 void CCustomResolverCache::Remove(TInt aIndex)
       
   267 	{
       
   268 	iResolvers[aIndex].Close();
       
   269 	iResolvers.Remove(aIndex);
       
   270 	}
       
   271 
       
   272 /** Search for a resolverUID. If found, return the NewL pointer and
       
   273 update time to live of the entry.
       
   274 @param aResolverUid the resolver to lookup
       
   275 @param aNewLFuncPtr output parameter. If lookup successful it has
       
   276 	the function pointer to instantiate the resolver.
       
   277 @return True if resolver is in cache. False otherwise.
       
   278 @post If cache hit, the timestamp of the entry is updated.
       
   279 */
       
   280 TBool CCustomResolverCache::CacheLookup(const TUid aResolverUid,
       
   281 										TProxyNewLPtr& aNewLFuncPtr)
       
   282 	{
       
   283 	TInt i = FindResolver(aResolverUid);
       
   284 	if (i >= 0)
       
   285 		{
       
   286 		aNewLFuncPtr = iResolvers[i].iNewLFuncPtr;
       
   287 		SetLastUseTime(iResolvers[i]);
       
   288 		}
       
   289 	return (i >= 0);
       
   290 	}
       
   291 
       
   292 /** Remove a resolver from cache.
       
   293 @param aResolverUid Identify the resolver to remove.
       
   294 @return ETrue if aResolverUid is found in cache. EFalse means the
       
   295 	resolver is not in cache.
       
   296 */
       
   297 TBool CCustomResolverCache::Remove(const TUid aResolverUid)
       
   298 	{
       
   299 	TInt i = FindResolver(aResolverUid);
       
   300 	if (i >= 0)
       
   301 		{
       
   302 		Remove(i);
       
   303 		}
       
   304 	return (i >= 0);
       
   305 	}
       
   306 
       
   307 /** Remove cached entries with flags set.
       
   308 @param aMask If an entry has any of the bits in aMask set, it is removed.
       
   309 */
       
   310 void CCustomResolverCache::RemoveItemsWithFlags(TUint32 aMask)
       
   311 	{
       
   312 	for (TInt i = iResolvers.Count() - 1; i >= 0; i--)
       
   313 		{
       
   314 		if (iResolvers[i].iFlags & aMask)
       
   315 			{
       
   316 			Remove(i);
       
   317 			}
       
   318 		}
       
   319 	}
       
   320 
       
   321 /** evict the least recently used entry in cache
       
   322 */
       
   323 void CCustomResolverCache::EvictLeastRecentlyUsed()
       
   324 	{
       
   325 	TUint curr = User::TickCount();
       
   326 	TInt index = 0; // set to first entry in cache.
       
   327 
       
   328 	for (TInt i = 1; i < iResolvers.Count(); i++)
       
   329 		{
       
   330 		RResolverCacheEntry& resolverEntry = iResolvers[i];
       
   331 		if (resolverEntry.ThisIsOlder(iResolvers[index], curr))
       
   332 			{
       
   333 			index = i;
       
   334 			}
       
   335 		}
       
   336 
       
   337 	Remove(index);
       
   338 	}
       
   339 
       
   340 /** Set the iLastUse field and iLruRank field of the entry.
       
   341 The iLruRank field serves as tie breaker when two entries are
       
   342 added within the same tick period.
       
   343 @param aEntry The entry to update.
       
   344 */
       
   345 void CCustomResolverCache::SetLastUseTime(RResolverCacheEntry& aEntry)
       
   346 	{
       
   347 	TUint curr = User::TickCount();
       
   348 	aEntry.iLastUse.iTicks = curr;
       
   349 	aEntry.iLruRank = 0;
       
   350 
       
   351 	if (curr == iMostRecentTimestamp)
       
   352 		{
       
   353 		// There are entries with same timestamp. So have to step
       
   354 		// through each cache entry to resolve senority.
       
   355 		for (TInt i = 0; i < iResolvers.Count(); i++)
       
   356 			{
       
   357 			RResolverCacheEntry& another = iResolvers[i];
       
   358 			if (another.iLastUse.iTicks == curr &&
       
   359 				another.iResolverUid != aEntry.iResolverUid &&
       
   360 				another.iLruRank >= aEntry.iLruRank)
       
   361 				{
       
   362 				aEntry.iLruRank = another.iLruRank + 1;
       
   363 				}
       
   364 			}
       
   365 		}
       
   366 	else
       
   367 		{
       
   368 		iMostRecentTimestamp = curr;
       
   369 		}
       
   370 	}
       
   371