--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingfw/msgsrvnstore/server/src/msventryfreepool.cpp Mon Jan 18 20:36:02 2010 +0200
@@ -0,0 +1,821 @@
+// Copyright (c) 2007-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:
+// HEADER FILES
+//
+//
+
+#include "msvcachevisiblefolder.h"
+#include "msvcacheindextableentry.h"
+#include "msvindexadapter.h"
+#include "msventryfreepool.h"
+#include "msvinifile.h"
+#include "MSVPANIC.H"
+
+
+/**
+ * MACRO DEFINITION
+ */
+#define BLOCK_SIZE 64
+#define PERCENTAGE_VALUE 100
+#define DEFAULT_MAXIMUM_CACHE_SIZE 1024
+#define DEFAULT_INITIAL_CACHE_SIZE_IN_PERCENTAGE 40
+#define DEFAULT_CACHE_INCREMENT_SIZE_IN_PERCENTAGE 20
+#define DEFAULT_CACHE_THRESHOLD_IN_PERCENTAGE 70
+#define CACHE_THRESHOLD_AFTER_FULL_CACHE 80
+#define PERCENTAGE_TO_SWAP_OUT 20
+
+/**
+ * LITERAL DEFINITION
+ */
+//Ini file which contains the cache setting
+#ifdef SYMBIAN_MESSAGESTORE_UNIT_TESTCODE
+ _LIT(KMSGINI, "C:\\private\\1000484b\\msgcache.ini");
+#else
+ _LIT(KMSGINI, "Z:\\private\\1000484b\\msgcache.ini");
+#endif
+
+
+//Ini keywords used for cache setting
+_LIT(KIniMsvInitialCacheCreation, "MsvInitialCacheCreation");
+_LIT(KIniMsvMaximumCacheSize, "MsvMaximumCacheSize");
+_LIT(KIniMsvCacheIncrement, "MsvCacheIncrement");
+_LIT(KIniMsvCacheThreshold, "MsvCacheThreshold");
+_LIT(KIniMsvSearchSortCache, "MsvSearchSortCachePercentage");
+
+
+/**
+ * STATIC MEMBER FUNCTION DEFINITION
+ */
+
+CMsvEntryFreePool* CMsvEntryFreePool::iMsvEntryFreePool = NULL;
+
+
+
+/**
+ * FUNCTION DEFINITION
+ */
+
+
+
+/**
+ * CMsvEntryFreePool()
+ *
+ * Constructor is kept private, since the class
+ * is singleton.
+ */
+CMsvEntryFreePool::CMsvEntryFreePool(TDblQue<CMsvCacheVisibleFolder>* aEntryCache):iEntryCache(aEntryCache)
+ {
+ }
+
+
+/**
+ * ~CMsvEntryFreePool()
+ *
+ * Default Destructor.
+ * The function should delete CMsvCacheEntry
+ * created so far. The destructor is made
+ * private so that only friend class can call it.
+ */
+
+CMsvEntryFreePool::~CMsvEntryFreePool()
+ {
+ if(iMsvTmpEntries.Count())
+ {
+ CommitTransaction();
+ }
+ if(iUsedCacheEntries.Count())
+ {
+ iUsedCacheEntries.ResetAndDestroy();
+ }
+ iUsedCacheEntries.Close();
+ if(iMsvEntries)
+ {
+ iMsvEntries->ResetAndDestroy();
+ iMsvEntries->Close();
+ }
+ delete iMsvEntries;
+ iMsvEntries = NULL;
+ iMsvTmpEntries.Close();
+ iMsvEntryFreePool = NULL;
+ }
+
+
+
+/**
+ * Instance()
+ *
+ * The function returns already created instance of
+ * this class to the caller. To create a new instance
+ * the caller should call CreateL(). If an instance of
+ * this object does not already exists, the function
+ * throws a panic EMsvFreePoolNotCreated in DEBUG mode.
+ */
+CMsvEntryFreePool* CMsvEntryFreePool::Instance()
+ {
+ __ASSERT_DEBUG(iMsvEntryFreePool!=NULL, PanicServer(EMsvFreePoolNotCreated));
+ return iMsvEntryFreePool;
+ }
+
+
+
+/**
+ * CreateL()
+ *
+ * The only way to create an object of this class.
+ * The function ensures that only one instance of
+ * the object is created. This is a static interface.
+ * The function is made private to ensure that only
+ * friend function can create instance of this class.
+ */
+CMsvEntryFreePool* CMsvEntryFreePool::CreateL(TDblQue<CMsvCacheVisibleFolder>* aEntryCache /*DEFAULT=NULL*/)
+ {
+ CMsvEntryFreePool* self = new (ELeave) CMsvEntryFreePool(aEntryCache);
+ //Push object in to cleanup stack so that it
+ // will be handles properly incase of a leave.
+ CleanupStack::PushL(self);
+
+ self->ConstructL();
+
+ //Pop from cleanupstack
+ CleanupStack::Pop(self);
+ iMsvEntryFreePool = self;
+
+ return self;
+ }
+
+
+
+
+/**
+ * ConstructL()
+ *
+ * The function is called from InstanceL() and used to
+ * initialize the instance of this class. It firsts reads
+ * cache configuration information from msgcache.ini file
+ * and stores them into member variable. It then allocates
+ * creates initial set of entries as described in conf file.
+ */
+void CMsvEntryFreePool::ConstructL()
+ {
+ // 1. Reading ini file
+
+ // If drive information is not mentioned in the
+ // filename, by default the class will check in
+ // C: drive. If the file is not found in C: it
+ // will check in Z: drive as well.
+ CMsvIniData* iniFile = NULL;
+ TRAPD(err, iniFile = CMsvIniData::NewL(KMSGINI));
+
+ // If we find the config file, read it. Else assign default values to cache configurations.
+ if(!err && iniFile)
+ {
+ CleanupStack::PushL(iniFile);
+
+ // Reading maximum cache size from ini file.
+ // Initially, iMsvMaximumCacheSize will have cache size in KB which
+ // will later be converted to number of cache entries possible.
+ User::LeaveIfError(iniFile->FindVar(KIniMsvMaximumCacheSize, iMsvMaximumCacheSize));
+
+ // Reading initial cache size from ini file.
+ // This is represented in terms of percentage
+ // of maximum cache size.
+ User::LeaveIfError(iniFile->FindVar(KIniMsvInitialCacheCreation, iMsvInitialCacheSize));
+
+ // Reading cache increment value from ini file.
+ // This is represented in terms of percentage
+ // of maximum cache size.
+ User::LeaveIfError(iniFile->FindVar(KIniMsvCacheIncrement, iMsvCacheIncrement));
+
+ // Reading threshold value from ini file
+ // This is represented in terms of percentage
+ // of maximum cache size.
+ User::LeaveIfError(iniFile->FindVar(KIniMsvCacheThreshold, iMsvCacheThreshold));
+
+ // Reading Search Sort Cache value in percentage from ini file
+ // This is represented in terms of percentage
+ // of maximum cache size.
+ User::LeaveIfError(iniFile->FindVar(KIniMsvSearchSortCache, iMsvSearchSortCache));
+
+ CleanupStack::PopAndDestroy(iniFile);
+ }
+
+ // Performing consistency check.
+ if(NULL == iMsvMaximumCacheSize)
+ {
+ iMsvMaximumCacheSize = DEFAULT_MAXIMUM_CACHE_SIZE;
+ }
+ if((iMsvInitialCacheSize > PERCENTAGE_VALUE) || (NULL == iMsvInitialCacheSize))
+ {
+ iMsvInitialCacheSize = DEFAULT_INITIAL_CACHE_SIZE_IN_PERCENTAGE;
+ }
+ if((iMsvCacheIncrement > PERCENTAGE_VALUE) || (NULL == iMsvCacheIncrement))
+ {
+ iMsvCacheIncrement = DEFAULT_CACHE_INCREMENT_SIZE_IN_PERCENTAGE;
+ }
+ if((iMsvCacheThreshold > PERCENTAGE_VALUE) || (NULL == iMsvCacheThreshold))
+ {
+ iMsvCacheThreshold = DEFAULT_CACHE_THRESHOLD_IN_PERCENTAGE;
+ }
+
+ //Determine maximum number of cache entries possible.
+ iMsvMaxEntries = ConvertMemToEntry(iMsvMaximumCacheSize * 1024);
+
+ // Approximate number of entries to be created when server starts.
+ TInt initialNumberOfEntries = (iMsvInitialCacheSize * iMsvMaxEntries) / 100;
+
+ // Since allocation is done in specific increment size, it is best
+ // to give the granularity as the increment count (not percentage here).
+ iMsvEntries = new(ELeave) RPointerArray<CMsvCacheEntry>((iMsvCacheIncrement * iMsvMaxEntries) / 100);
+
+ // Create the initial number of cache entries.
+ // iMsvCacheNumberOfEntriesCreated will store
+ // number of CMsvCacheEntry created so far.
+ for (iMsvCacheNumberOfEntriesCreated = 0; iMsvCacheNumberOfEntriesCreated < initialNumberOfEntries ; iMsvCacheNumberOfEntriesCreated++)
+ {
+ iMsvEntries->AppendL(CMsvCacheEntry::NewL());
+ }
+
+ // Percentage of allocated memory utilized so far.
+ iMsvPercentageAllocated = iMsvInitialCacheSize;
+
+ }
+
+
+
+void CMsvEntryFreePool::SetEssentialParam(TDblQue<CMsvCacheVisibleFolder>* aEntryCache, CMsvIndexAdapter* aAdapterObj)
+ {
+ iEntryCache = aEntryCache;
+ iAdapter = aAdapterObj;
+ }
+
+
+
+/**
+ * ConvertMemToEntry()
+ * @param aMem: Memory size in bytes.
+ * @return TInt: the number of entries that the free pool can have
+ * given a memory size in bytes.
+ *
+ * The function calculates the number of cache entries possible in
+ * the free pool given the memory size.
+ */
+TInt CMsvEntryFreePool::ConvertMemToEntry(TInt aMem)
+ {
+ //This calculation is based on the fact that not all cache entries will have
+ //children as most are leaf nodes. Our assumption is that 20% of the entries
+ //will have an RArray, i.e. have children. The following formula determines
+ //maximum number of entries that the cache can have as:
+ // sizeof(CMsvCacheEntry) = 120 bytes;
+ // sizeof(RArray<TMsvId>) = 36 bytes;
+ // sizeof(RArray<TMsvId>*) = 4 bytes;
+ // => multiplying factor = (80*120 + 20*156)/(120*100) = 1.06
+ return ( (aMem) / (1.06*sizeof(CMsvCacheEntry)) );
+ }
+
+
+
+/**
+ * Destroy()
+ * @param CMsvEntryFreePool: The object to be destroyed.
+ *
+ * Only way to destroy an object of this class in debug
+ * mode. The functions raises a panic when amount of
+ * cache entry created so far is not same as amount of
+ * entry the object currently holds. The function is
+ * declared private so that only friend class can call this.
+ *
+ * In release mode destructor should be called directly.
+ */
+#ifdef _DEBUG
+
+void CMsvEntryFreePool::Destroy(CMsvEntryFreePool* aFreePoolInstance)
+ {
+ if(NULL==aFreePoolInstance)
+ return;
+
+ if(aFreePoolInstance->iMsvTmpEntries.Count())
+ {
+ aFreePoolInstance->CommitTransaction();
+ }
+
+ // Check if the number of entries created so far is same
+ // as amount of entry currently present with freepool (iMsvEntries).
+ __ASSERT_DEBUG(aFreePoolInstance->iMsvCacheNumberOfEntriesCreated==aFreePoolInstance->iMsvEntries->Count(), User::Invariant());
+
+ delete aFreePoolInstance;
+ }
+
+#endif
+
+
+
+/**
+ * EntryL()
+ * @param None.
+ * @return CMsvCacheEntry*: An unused CMsvCacheEntry.
+ *
+ * Returns one unused entry from the freepool. If
+ * freepool is empty, it checks if a new entry can
+ * be allocated and returned. If amount of new entry
+ * created equals the maximum allowed limit (as set
+ * by the licencees in .ini file), the function calls
+ * SwapEntries to swap few entries from cache.
+ * If no entries can be allocated or swapped, it
+ * leaves with KErrNoMemory.
+ */
+CMsvCacheEntry* CMsvEntryFreePool::EntryL()
+ {
+ // Number of entries available in freepool.
+ TInt count = iMsvEntries->Count();
+ CMsvCacheEntry* entry = NULL;
+
+ // Is entry available in freepool?
+ if (0 < count)
+ {
+ // Just return the last entry.
+ entry = (*iMsvEntries)[--count];
+ iMsvEntries->Remove(count);
+ return entry;
+ }
+ else
+ {
+ // Can we still allocate fresh memory?
+ if(iMsvMaxEntries > iMsvCacheNumberOfEntriesCreated)
+ {
+ ++iMsvCacheNumberOfEntriesCreated;
+ return CMsvCacheEntry::NewL();
+ }
+ //Otherwise swap out BLOCK_SIZE entries to free up space.
+ //Form an entry from this memory and return it.
+ else
+ {
+ SwapEntriesL(BLOCK_SIZE);
+ count = iMsvEntries->Count();
+ if(count)
+ {
+ entry = (*iMsvEntries)[--count];
+ iMsvEntries->Remove(count);
+ return entry;
+ }
+ else
+ {
+ ++iMsvCacheNumberOfEntriesCreated;
+ return CMsvCacheEntry::NewL();
+ }
+ }
+ }
+ }
+
+
+
+/**
+ * ReleaseEntry()
+ * @param CMsvCacheEntry* : Entry to be release to freepool.
+ * @return None.
+ *
+ * The function resets and appends the passed
+ * entry to freepool so that it can be reused.
+ */
+void CMsvEntryFreePool::ReleaseEntry(CMsvCacheEntry* aMsvCacheEntry, TBool aBypassTransaction /* DEFAULT=EFalse*/)
+ {
+ if( NULL == aMsvCacheEntry )
+ {
+ return;
+ }
+
+ if(isTransactionOpen && (EFalse == aBypassTransaction))
+ {
+ iMsvTmpEntries.Append(aMsvCacheEntry);
+ }
+ else
+ {
+ // 1. Reset the entry data.
+ aMsvCacheEntry->ResetEntry();
+
+ // 2. Append entry to the freepool.
+ iMsvEntries->Append(aMsvCacheEntry);
+ }
+ }
+
+
+
+void CMsvEntryFreePool::ReleaseEntryWithoutTransaction(CMsvCacheEntry* aMsvCacheEntry)
+ {
+ if(NULL == aMsvCacheEntry)
+ {
+ return;
+ }
+
+ aMsvCacheEntry->ResetEntry();
+ TRAPD(Err, iMsvEntries->AppendL(aMsvCacheEntry));
+ if(Err)
+ {
+ delete aMsvCacheEntry;
+ iMsvCacheNumberOfEntriesCreated--;
+ }
+ }
+
+
+
+
+
+/**
+ * ReleaseEntrySet()
+ * @param RPointerArray<CMsvCacheEntry>* : Entry set to be released.
+ * @return None.
+ *
+ * The function resets and appends the passed set
+ * of entries to freepool so that it can be reused.
+ */
+void CMsvEntryFreePool::ReleaseEntrySet(RPointerArray<CMsvCacheEntry>& aMsvCacheEntryArray)
+ {
+ TRAPD(error, DoReleaseEntrySetL(aMsvCacheEntryArray));
+ if(error)
+ {
+ // 1. delete the remaining cache entries from aMsvCacheEntryArray
+ // 2. reduce appropriate variables in CMsvEntryFreePool
+ TInt count = aMsvCacheEntryArray.Count();
+ iMsvCacheNumberOfEntriesCreated -= count;
+ while(count)
+ {
+ // 1. Reset the entry data.
+ aMsvCacheEntryArray[--count]->ResetEntry();
+
+ // 2. Delete the memory allocated to the cache entry.
+ delete aMsvCacheEntryArray[count];
+ aMsvCacheEntryArray.Remove(count);
+ }
+ }
+ }
+
+
+/**
+ * DoReleaseEntrySetL()
+ * @param RPointerArray<CMsvCacheEntry>* : Entry set to be released.
+ * @return None.
+ *
+ * The function resets and appends the passed set
+ * of entries to freepool so that it can be reused.
+ */
+void CMsvEntryFreePool::DoReleaseEntrySetL(RPointerArray<CMsvCacheEntry>& aMsvCacheEntryArray)
+ {
+ TInt count = aMsvCacheEntryArray.Count();
+ while ( 0 < count)
+ {
+ if(isTransactionOpen)
+ {
+ iMsvTmpEntries.AppendL(aMsvCacheEntryArray[--count]);
+ }
+ else
+ {
+ // 1. Reset the entry data.
+ aMsvCacheEntryArray[--count]->ResetEntry();
+
+#ifdef SYMBIAN_MESSAGESTORE_UNIT_TESTCODE
+ if(iReleaseError)
+ {
+ if(iReleaseErrorOffset == count)
+ {
+ iReleaseError = EFalse;
+ User::Leave(KErrNoMemory); // an arbitrary error purely for testing purpose
+ }
+ }
+#endif
+ // 2. Add entry to the freepool.
+ iMsvEntries->AppendL(aMsvCacheEntryArray[count]);
+ }
+
+ // 3. Remove entry from the input array.
+ aMsvCacheEntryArray.Remove(count);
+ }
+ }
+
+
+
+/**
+ *
+ */
+void CMsvEntryFreePool::RollbackTransaction()
+ {
+ TInt count = iMsvTmpEntries.Count();
+ while(0 < count)
+ {
+ if(NULL != iAdapter)
+ {
+ TRAP_IGNORE(iAdapter->AddEntryNoVisibleL(iMsvTmpEntries[--count]));
+ }
+ }
+ iMsvTmpEntries.Reset();
+ isTransactionOpen = EFalse;
+ }
+
+
+/**
+ *
+ */
+void CMsvEntryFreePool::CommitTransaction()
+ {
+ TInt count = iMsvTmpEntries.Count();
+ while(0 < count)
+ {
+ iMsvTmpEntries[--count]->ResetEntry();
+ iMsvEntries->Append(iMsvTmpEntries[count]);
+ }
+ iMsvTmpEntries.Reset();
+ isTransactionOpen = EFalse;
+ }
+
+
+
+/**
+ * SwapEntriesL()
+ * @param TInt: number of entries to be swapped out.
+ * @return None.
+ *
+ * Swap a specified amount of entries from cache.
+ * The function is called by GetEntry() when it
+ * cannot return an unused entry since freepool is
+ * empty.
+ */
+void CMsvEntryFreePool::SwapEntriesL(TInt aEntriesToSwap)
+ {
+ if(!iEntryCache)
+ {
+ User::Leave(KErrArgument);
+ }
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(*iEntryCache);
+
+ dqIter.SetToLast();
+ TInt entriesReleased = 0;
+ TBool isFolderEmpty;
+
+ while( ((folderNode = dqIter--) != NULL) && (entriesReleased < aEntriesToSwap)
+#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ //We do not swap out Local service and root folder node.
+ && (KMsvLocalServiceIndexEntryId) != UnmaskTMsvId(folderNode->GetFolderId())
+ && (KMsvRootIndexEntryId != folderNode->GetFolderId())
+#else
+ && (KMsvLocalServiceIndexEntryId) != folderNode->GetFolderId()
+ && (KMsvRootIndexEntryId != folderNode->GetFolderId())
+#endif
+ )
+ {
+ isFolderEmpty = EFalse;
+ //Attempt to reclaim aEntriesToSwap from a single folder.
+ //The number of entries swapped out can be more than aEntriesToSwap.
+ entriesReleased += folderNode->ReleaseBlocks((aEntriesToSwap - entriesReleased), isFolderEmpty);
+ #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)
+ TMsvId folderId = UnmaskTMsvId(folderNode->GetFolderId());
+ #else
+ TMsvId folderId = folderNode->GetFolderId();
+ #endif
+
+ if(isFolderEmpty && !folderNode->GetChildrenFromVisibleFolder() && folderId > KMsvDeletedEntryFolderEntryId )
+ {
+ folderNode->iDlink.Deque();
+ delete folderNode;
+ break;
+ }
+ }
+ }
+
+
+
+
+/**
+ * IsAllocationRequiredL()
+ * @param None.
+ * @return TBool: ETrue if the free pool has reached its threshold,
+ * EFalse if otherwise.
+ *
+ * The function return ETrue if the free pool has reached its
+ * threshold and EFalse if otherwise.
+ */
+TBool CMsvEntryFreePool::IsAllocationRequiredL()
+ {
+ // Size of actual cache data structure.
+ iMsvCacheSize = CacheSizeL();
+
+ // Total cache size includes the size of freepool as well.
+ TInt totalCacheSize = iMsvCacheSize + iMsvEntries->Count()*sizeof(CMsvCacheEntry);
+
+ //Check if the size of the folder list exceeds or equals the threshold.
+ //If all of the cache memory has been used up, checking is done against
+ //the secondary threshold value.
+ if( PERCENTAGE_VALUE == iMsvPercentageAllocated )
+ {
+ if(iMsvCacheSize > (totalCacheSize * CACHE_THRESHOLD_AFTER_FULL_CACHE/100))
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+ else
+ {
+ if(iMsvCacheSize > (totalCacheSize * iMsvCacheThreshold/100))
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ }
+ }
+
+
+
+/**
+ * CacheSizeL()
+ * @param None.
+ * @return TInt: the size of the cache data structure in bytes.
+ *
+ * The function returns the size of the cache data structure in bytes,
+ * excluding the memory occupied by the free entries in the freepool.
+ */
+TInt CMsvEntryFreePool::CacheSizeL()
+ {
+ if(!iEntryCache)
+ {
+ User::Leave(KErrArgument);
+ }
+ CMsvCacheVisibleFolder* folderNode = NULL;
+ TDblQueIter<CMsvCacheVisibleFolder> dqIter(*iEntryCache);
+ TInt cacheSize = 0;
+ TInt folderCount = 0;
+
+ //Calculate the size of the whole folder list structure.
+ //This includes the size required for the data structures,
+ // Eg: index table, block of entries etc.
+ dqIter.SetToFirst();
+ while ((folderNode = dqIter++) != NULL)
+ {
+ ++folderCount;
+ RPointerArray<CMsvCacheIndexTableEntry> *indexTable = folderNode->GetIndexTableEntry();
+ //Number of blocks in the indextable, i.e. number of indextable entries.
+ TInt count = indexTable->Count();
+ for(TInt index = 0; index < count; ++index)
+ {
+ TInt entryCount = (*indexTable)[index]->Size();
+ cacheSize += entryCount * (sizeof(CMsvCacheEntry) * 1.06);
+ //Include the size of the details and description buffers of a cache entry.
+ //Size of buffers and members of TMsvEntry is the same.
+ //Description and details each have standard size of 15.
+ cacheSize += (2*15) * entryCount;
+ }
+ //Size of data structure for the blocks.
+ cacheSize += count * sizeof(CMsvCacheIndexTableEntry);
+ }
+ //Size of the data structure for index tables.
+ cacheSize += folderCount * sizeof(CMsvCacheVisibleFolder); //bytes
+ return cacheSize;
+ }
+
+
+
+/**
+ * AllocateMemoryL()
+ * @param None.
+ * @return None.
+ *
+ * The function expands the cache free pool when it has reached its threshold.
+ * If all of the memory has not been used up yet, it allocates the entries as per
+ * the next increment. It allocates memory again if threshold is still being exceeded.
+ * Swapping might be performed to maintain the threshold.
+ * If all of the memory has been used up, it swaps out (100-iMsvCacheThreshold)% entries
+ * from cache.
+ */
+void CMsvEntryFreePool::AllocateMemoryL()
+ {
+ //Total cache size includes the size of freepool as well.
+ TInt totalCacheSize = iMsvCacheSize + iMsvEntries->Count()*sizeof(CMsvCacheEntry);
+
+ // Check if entire memory is not yet allocated to cache.
+ if(PERCENTAGE_VALUE > iMsvPercentageAllocated)
+ {
+ //Yes, it has not been used up. Calculate the percentage allocation done till now.
+ TInt actualPercentage = (totalCacheSize * 100/1024)/iMsvMaximumCacheSize;
+ while(actualPercentage >= iMsvPercentageAllocated && iMsvPercentageAllocated < PERCENTAGE_VALUE)
+ {
+ iMsvPercentageAllocated += iMsvCacheIncrement;
+ }
+ if(PERCENTAGE_VALUE < iMsvPercentageAllocated)
+ {
+ iMsvPercentageAllocated = PERCENTAGE_VALUE;
+ }
+
+ //Calculate how much memory has to be allocated in terms of cache entries.
+ TInt memoryDiff = iMsvMaximumCacheSize*1024*(iMsvPercentageAllocated - actualPercentage)/100;
+ if(memoryDiff > 0)
+ {
+ TInt entriesToCreate = ConvertMemToEntry(memoryDiff);
+ for(TInt index = 0; index < entriesToCreate; ++index)
+ {
+ iMsvEntries->AppendL(CMsvCacheEntry::NewL());
+ ++iMsvCacheNumberOfEntriesCreated;
+ }
+ }
+ //If the cache data structure size still exceeds the threshold go for
+ //the next increment allocation.
+ totalCacheSize = iMsvCacheSize + iMsvEntries->Count()*sizeof(CMsvCacheEntry);
+ if( (totalCacheSize * iMsvCacheThreshold)/100 < iMsvCacheSize )
+ {
+ //If all of the memory has been used up now, swap out entries.
+ if( PERCENTAGE_VALUE == iMsvPercentageAllocated )
+ {
+ SwapEntriesL(PERCENTAGE_TO_SWAP_OUT*iMsvMaxEntries/100);
+ }
+ //Otherwise calculate the number of entries in the increment and allocate.
+ else
+ {
+ TInt previousPercent = iMsvPercentageAllocated;
+ iMsvPercentageAllocated += iMsvCacheIncrement;
+ if(PERCENTAGE_VALUE < iMsvPercentageAllocated)
+ {
+ iMsvPercentageAllocated = PERCENTAGE_VALUE;
+ }
+ memoryDiff = iMsvMaximumCacheSize*1024*(iMsvPercentageAllocated - previousPercent)/100;
+ TInt entriesToCreate = ConvertMemToEntry(memoryDiff);
+ for(TInt index = 0; index < entriesToCreate; ++index)
+ {
+ iMsvEntries->AppendL(CMsvCacheEntry::NewL());
+ ++iMsvCacheNumberOfEntriesCreated;
+ }
+ }
+ }
+ }
+ else
+ {
+ //All of the cache memory has been used. Go for swapping out of entries from the
+ //cache data structure to free up memory.
+ SwapEntriesL(PERCENTAGE_TO_SWAP_OUT*iMsvMaxEntries/100);
+ }
+
+ //Calculate the number of entries that can be formed from the remaining memory.
+ if( PERCENTAGE_VALUE == iMsvPercentageAllocated )
+ {
+ iMsvMaxEntries = iMsvCacheNumberOfEntriesCreated;
+ }
+ else
+ {
+ iMsvMaxEntries = iMsvCacheNumberOfEntriesCreated + ConvertMemToEntry((iMsvMaximumCacheSize * 1024) * (100-iMsvPercentageAllocated)/100);
+ }
+ }
+
+
+
+/**
+ * FlushExcessMemory()
+ */
+void CMsvEntryFreePool::FlushExcessMemory()
+ {
+ TInt count = iUsedCacheEntries.Count();
+ if(count)
+ {
+ CMsvCacheEntry *entry = NULL;
+ while(count)
+ {
+ entry = iUsedCacheEntries[0];
+ iUsedCacheEntries.Remove(0);
+ if(iMsvMaxEntries < iMsvCacheNumberOfEntriesCreated)
+ {
+ delete entry;
+ iMsvCacheNumberOfEntriesCreated--;
+ }
+ else
+ {
+ entry->ResetEntry();
+ iMsvEntries->Append(entry);
+ }
+ --count;
+ }
+ iUsedCacheEntries.Reset();
+ }
+ }
+
+
+
+void CMsvEntryFreePool::RoutineFreePoolCleanUpL()
+ {
+ FlushExcessMemory();
+ TInt excessMemory = ExcessMemoryAllocated();
+ if(excessMemory)
+ {
+ SwapEntriesL(excessMemory);
+ }
+ }