lowlevellibsandfws/pluginfw/Framework/frame/resolvercache.cpp
changeset 0 e4d67989cc36
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lowlevellibsandfws/pluginfw/Framework/frame/resolvercache.cpp	Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,371 @@
+// Copyright (c) 2008-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:
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <e32def.h>
+#include <e32cmn.h>
+#include <hal.h>
+#include "EComDebug.h"
+#include "ImplementationInformation.h"  // CompareTUidValues
+#include "callback.h"
+#include "resolvercache.h"
+#include "EComPatchDataConstantv2.h"
+
+const TInt KCacheQueueGranularity = 4;
+
+//
+// TCounterTicks class
+//
+inline TCounterTicks::TCounterTicks(TUint aTicks)
+	: iTicks(aTicks)
+	{
+	}
+
+/** This substraction calculate elapsed ticks: aEndTick - this */
+inline
+TUint TCounterTicks::ElapsedSinceThis(TUint aEndTick) const
+	{
+	TUint diff;
+	if (aEndTick < iTicks) // wrap around occurred
+		{
+		diff = KMaxTUint - iTicks + aEndTick + 1;
+		}
+	else
+		{
+		diff = aEndTick - iTicks;
+		}
+	return diff;
+	}
+
+/** default constructor which initializes all member data to 0. */
+RResolverCacheEntry::RResolverCacheEntry()
+	: iLastUse( TCounterTicks(0) ), iLruRank(0), iResolverUid(KNullUid),
+	iNewLFuncPtr(NULL), iFlags(EEntryFlagsNone)
+	{
+	iLibrary.SetHandle(KNullHandle);
+	}
+
+/** construct RResolverCacheEntry with specific data
+@param aResolverUid TUid of the resolver.
+@param aLib RLibrary with handle open on the resolver DLL.
+@param aNewL Function ptr to instantiate the resolver.
+@param aFlags Special conditions about the cache entry.
+*/
+RResolverCacheEntry::RResolverCacheEntry(const TUid aResolverUid,
+										RLibrary aLib,
+										TProxyNewLPtr aNewL,
+										TUint32 aFlags)
+	: iLastUse( TCounterTicks(0) ), iLruRank(0), iResolverUid(aResolverUid),
+	iNewLFuncPtr(aNewL), iFlags(aFlags)
+	{
+	iLibrary.SetHandle(aLib.Handle());
+	}
+
+/** unallocate resources owned by the RResolverCacheEntry object */
+void RResolverCacheEntry::Close()
+	{
+	iLibrary.Close();
+	}
+
+/** This method compares two RResolverCacheEntry objects.
+@param aEntry1 first RResolverCacheEntry object.
+@param aEntry2 second RResolverCacheEntry object.
+@return 0 means the two objects are equal.
+        positive value means first object is greater than the second.
+		negative vlaue means second object is greater than the first.
+*/
+TInt RResolverCacheEntry::CompareUid(const RResolverCacheEntry& aEntry1,
+								     const RResolverCacheEntry& aEntry2)
+	{
+	return CompareTUidValues(aEntry1.iResolverUid.iUid,
+							 aEntry2.iResolverUid.iUid);
+	}
+
+/** Compare the age of two cache entries.
+@param aOther The RResolverCacheEntry to compare with.
+@param aCurrTick The current system tick. It simplifies handling
+	of system tick wrap around to zero.
+@return ETrue means "this" object is older than aOther.
+	EFalse means aOther is older than "this".
+*/
+TBool RResolverCacheEntry::ThisIsOlder(const RResolverCacheEntry& aOther,
+										TUint aCurrTick) const
+	{
+	if (iLastUse.iTicks == aOther.iLastUse.iTicks)
+		{
+		return iLruRank < aOther.iLruRank;
+		}
+
+	// Because of counter wrap around, it is not safe to directly
+	// compare the two ticks. Drag in the current system tick.
+	return iLastUse.ElapsedSinceThis(aCurrTick) >
+			aOther.iLastUse.ElapsedSinceThis(aCurrTick);
+	}
+
+//=================================
+// CCustomResolverCache class
+//=================================
+
+/** CCustomResolverCache constructor
+@param aCacheSize Maximum number of entries allowed to cache.
+*/
+CCustomResolverCache::CCustomResolverCache(TUint32 aCacheSize)
+	: CTimer(CActive::EPriorityStandard),
+	iResolvers(KCacheQueueGranularity), 
+	iMaxCacheSize(aCacheSize)
+	{
+	}
+
+/** static factory method to instantiate CCustomResolverCache
+@param aCacheSize Maximum number of entries allowed to cache.
+@param aCacheTimeout Cache timeout in microseconds.
+@leave Any of the system wide error codes.
+*/
+CCustomResolverCache* CCustomResolverCache::NewL(TUint32 aCacheSize, TUint32 aCacheTimeout)
+	{
+	CCustomResolverCache* self = new (ELeave) CCustomResolverCache(aCacheSize);
+	CleanupStack::PushL(self);
+	self->ConstructL(aCacheTimeout);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** Standard two phase construction to complete construction of
+the CCustomResolverCache object.
+@param aCacheTimeout Cache timeout in microseconds.
+@leave Any of the system wide error codes.
+*/
+void CCustomResolverCache::ConstructL(TUint32 aCacheTimeout)
+	{
+	User::LeaveIfError(HAL::Get(HALData::ESystemTickPeriod,
+								iSystemTickPeriod));
+	iEntryTimeToLive = (aCacheTimeout + iSystemTickPeriod - 1) / iSystemTickPeriod;
+
+	CTimer::ConstructL();
+	CActiveScheduler::Add(this);
+	}
+
+/** CCustomResolverCache destructor */
+CCustomResolverCache::~CCustomResolverCache()
+	{
+	Cancel();
+	for (TInt i = iResolvers.Count() - 1; i >= 0; i--)
+		{
+		iResolvers[i].Close();
+		}
+	iResolvers.Reset();
+	}
+
+/** Implement the CActive RunL pure virtual */
+void CCustomResolverCache::RunL()
+	{
+	TUint currTickCount = User::TickCount();
+	TUint lruAge = 0;
+
+	for (TInt i = iResolvers.Count() - 1; i >= 0; i--)
+		{
+		RResolverCacheEntry& resolverEntry = iResolvers[i];
+		TUint age = resolverEntry.iLastUse.ElapsedSinceThis(currTickCount);
+		if (age >= iEntryTimeToLive)
+			{
+			resolverEntry.Close();
+			iResolvers.Remove(i);
+			}
+		else if (age > lruAge)
+			{
+			lruAge = age;
+			}
+		}
+
+	if (iResolvers.Count() > 0)
+		{
+		After( iSystemTickPeriod * (iEntryTimeToLive - lruAge + 1) );
+		}
+
+#ifdef __ECOMSERVER_TESTING__
+	// In unit testing notify test bed that cache timer has fired.
+	iTimerExpireCB.CallBack(0, NULL);
+#endif
+	}
+
+/** Search of a resolver UID in cache
+@param aResolverUid the resolver to search for.
+@return If find is successful, index of the resolver in RArray of cached resolvers.
+		Return KErrNotFound if resolver is not in cache.
+*/
+TInt CCustomResolverCache::FindResolver(const TUid aResolverUid) const
+	{
+	RResolverCacheEntry trgt;
+	trgt.iResolverUid = aResolverUid;
+	TLinearOrder<RResolverCacheEntry> comparator(RResolverCacheEntry::CompareUid);
+	return iResolvers.FindInOrder(trgt, comparator);
+	}
+
+/** Add a resolver library to cache 
+@param aResolverUid Implementation UID of the resolver.
+@param aLib	The RLibrary object which has the resolver loaded. The handle
+	of the RLibrary is owned by the cache if call is successful.
+@param aNewL value for the iNewLFuncPtr member data of RResolverCacheEntry.
+@param aFlags value for the iFlags member data of RResolverCacheEntry.
+@return KErrNone if the data is added to cache.
+	KErrNoMemory if fail to insert the data in RArray.
+*/
+TInt CCustomResolverCache::CacheResolver(const TUid aResolverUid,
+										  RLibrary aLib,
+										  TProxyNewLPtr aNewL,
+										  TUint32 aFlags)
+	{
+	if (iResolvers.Count() == iMaxCacheSize)
+		{
+		EvictLeastRecentlyUsed();
+		}
+
+	RResolverCacheEntry entry(aResolverUid, aLib, aNewL, aFlags);
+	SetLastUseTime(entry);
+
+#ifdef ECOM_TRACE
+	__ECOM_TRACE2("ECOM: adding custom resolver 0x%X to cache. New queue size will be %d.\n", aResolverUid.iUid, 1 + iResolvers.Count());
+#endif
+
+	TLinearOrder<RResolverCacheEntry> comparator(RResolverCacheEntry::CompareUid);
+	TInt err = iResolvers.InsertInOrder(entry, comparator);
+
+	// if cache was empty before need to start timer
+	if (err == KErrNone && ! IsActive())
+		{
+		After( iSystemTickPeriod * (iEntryTimeToLive + 1) );
+		}
+	return err;
+	}
+
+/** Check if both queue size and cache timeout are non zero  */
+TBool CCustomResolverCache::CachingEnabled() const
+	{
+	return (iMaxCacheSize && iEntryTimeToLive);
+	}
+
+/** Remove a cached entry
+@param aIndex position of entry in the array.
+*/
+void CCustomResolverCache::Remove(TInt aIndex)
+	{
+	iResolvers[aIndex].Close();
+	iResolvers.Remove(aIndex);
+	}
+
+/** Search for a resolverUID. If found, return the NewL pointer and
+update time to live of the entry.
+@param aResolverUid the resolver to lookup
+@param aNewLFuncPtr output parameter. If lookup successful it has
+	the function pointer to instantiate the resolver.
+@return True if resolver is in cache. False otherwise.
+@post If cache hit, the timestamp of the entry is updated.
+*/
+TBool CCustomResolverCache::CacheLookup(const TUid aResolverUid,
+										TProxyNewLPtr& aNewLFuncPtr)
+	{
+	TInt i = FindResolver(aResolverUid);
+	if (i >= 0)
+		{
+		aNewLFuncPtr = iResolvers[i].iNewLFuncPtr;
+		SetLastUseTime(iResolvers[i]);
+		}
+	return (i >= 0);
+	}
+
+/** Remove a resolver from cache.
+@param aResolverUid Identify the resolver to remove.
+@return ETrue if aResolverUid is found in cache. EFalse means the
+	resolver is not in cache.
+*/
+TBool CCustomResolverCache::Remove(const TUid aResolverUid)
+	{
+	TInt i = FindResolver(aResolverUid);
+	if (i >= 0)
+		{
+		Remove(i);
+		}
+	return (i >= 0);
+	}
+
+/** Remove cached entries with flags set.
+@param aMask If an entry has any of the bits in aMask set, it is removed.
+*/
+void CCustomResolverCache::RemoveItemsWithFlags(TUint32 aMask)
+	{
+	for (TInt i = iResolvers.Count() - 1; i >= 0; i--)
+		{
+		if (iResolvers[i].iFlags & aMask)
+			{
+			Remove(i);
+			}
+		}
+	}
+
+/** evict the least recently used entry in cache
+*/
+void CCustomResolverCache::EvictLeastRecentlyUsed()
+	{
+	TUint curr = User::TickCount();
+	TInt index = 0; // set to first entry in cache.
+
+	for (TInt i = 1; i < iResolvers.Count(); i++)
+		{
+		RResolverCacheEntry& resolverEntry = iResolvers[i];
+		if (resolverEntry.ThisIsOlder(iResolvers[index], curr))
+			{
+			index = i;
+			}
+		}
+
+	Remove(index);
+	}
+
+/** Set the iLastUse field and iLruRank field of the entry.
+The iLruRank field serves as tie breaker when two entries are
+added within the same tick period.
+@param aEntry The entry to update.
+*/
+void CCustomResolverCache::SetLastUseTime(RResolverCacheEntry& aEntry)
+	{
+	TUint curr = User::TickCount();
+	aEntry.iLastUse.iTicks = curr;
+	aEntry.iLruRank = 0;
+
+	if (curr == iMostRecentTimestamp)
+		{
+		// There are entries with same timestamp. So have to step
+		// through each cache entry to resolve senority.
+		for (TInt i = 0; i < iResolvers.Count(); i++)
+			{
+			RResolverCacheEntry& another = iResolvers[i];
+			if (another.iLastUse.iTicks == curr &&
+				another.iResolverUid != aEntry.iResolverUid &&
+				another.iLruRank >= aEntry.iLruRank)
+				{
+				aEntry.iLruRank = another.iLruRank + 1;
+				}
+			}
+		}
+	else
+		{
+		iMostRecentTimestamp = curr;
+		}
+	}
+