diff -r 000000000000 -r 8e480a14352b messagingfw/msgsrvnstore/server/src/msventryfreepool.cpp --- /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* 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* 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((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* 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) = 36 bytes; + // sizeof(RArray*) = 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* : 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& 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* : 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& 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 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 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 *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); + } + }