messagingfw/msgsrvnstore/server/src/msventryfreepool.cpp
changeset 0 8e480a14352b
child 36 e7635922c074
equal deleted inserted replaced
-1:000000000000 0:8e480a14352b
       
     1 // Copyright (c) 2007-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 // HEADER FILES
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "msvcachevisiblefolder.h"
       
    19 #include "msvcacheindextableentry.h"
       
    20 #include "msvindexadapter.h"
       
    21 #include "msventryfreepool.h"
       
    22 #include "msvinifile.h"
       
    23 #include "MSVPANIC.H"
       
    24 
       
    25 
       
    26 /**
       
    27  * MACRO DEFINITION
       
    28  */
       
    29 #define BLOCK_SIZE 64
       
    30 #define PERCENTAGE_VALUE 100
       
    31 #define DEFAULT_MAXIMUM_CACHE_SIZE 1024
       
    32 #define DEFAULT_INITIAL_CACHE_SIZE_IN_PERCENTAGE 40
       
    33 #define DEFAULT_CACHE_INCREMENT_SIZE_IN_PERCENTAGE 20
       
    34 #define DEFAULT_CACHE_THRESHOLD_IN_PERCENTAGE 70
       
    35 #define CACHE_THRESHOLD_AFTER_FULL_CACHE 80
       
    36 #define PERCENTAGE_TO_SWAP_OUT 20
       
    37 
       
    38 /**
       
    39  * LITERAL DEFINITION
       
    40  */
       
    41 //Ini file which contains the cache setting
       
    42 #ifdef SYMBIAN_MESSAGESTORE_UNIT_TESTCODE
       
    43 	_LIT(KMSGINI, "C:\\private\\1000484b\\msgcache.ini");
       
    44 #else
       
    45 	_LIT(KMSGINI, "Z:\\private\\1000484b\\msgcache.ini");
       
    46 #endif
       
    47 	
       
    48 
       
    49 //Ini keywords used for cache setting
       
    50 _LIT(KIniMsvInitialCacheCreation, "MsvInitialCacheCreation");
       
    51 _LIT(KIniMsvMaximumCacheSize, "MsvMaximumCacheSize");
       
    52 _LIT(KIniMsvCacheIncrement, "MsvCacheIncrement");
       
    53 _LIT(KIniMsvCacheThreshold, "MsvCacheThreshold");
       
    54 _LIT(KIniMsvSearchSortCache, "MsvSearchSortCachePercentage");
       
    55 
       
    56 
       
    57 /**
       
    58  * STATIC MEMBER FUNCTION DEFINITION
       
    59  */
       
    60  
       
    61 CMsvEntryFreePool* CMsvEntryFreePool::iMsvEntryFreePool = NULL;
       
    62 
       
    63 
       
    64 
       
    65 /**
       
    66  * FUNCTION DEFINITION
       
    67  */
       
    68  
       
    69  
       
    70  
       
    71 /**
       
    72  * CMsvEntryFreePool()
       
    73  *
       
    74  * Constructor is kept private, since the class
       
    75  * is singleton.
       
    76  */
       
    77 CMsvEntryFreePool::CMsvEntryFreePool(TDblQue<CMsvCacheVisibleFolder>* aEntryCache):iEntryCache(aEntryCache)
       
    78 	{
       
    79 	}
       
    80 
       
    81 
       
    82 /**
       
    83  * ~CMsvEntryFreePool()
       
    84  *
       
    85  * Default Destructor. 
       
    86  * The function should delete CMsvCacheEntry
       
    87  * created so far. The destructor is made 
       
    88  * private so that only friend class can call it.
       
    89  */
       
    90  
       
    91 CMsvEntryFreePool::~CMsvEntryFreePool()
       
    92 	{
       
    93 	if(iMsvTmpEntries.Count())
       
    94 		{
       
    95 		CommitTransaction();
       
    96 		}
       
    97 	if(iUsedCacheEntries.Count())
       
    98 		{
       
    99 		iUsedCacheEntries.ResetAndDestroy();
       
   100 		}
       
   101 	iUsedCacheEntries.Close();
       
   102 	if(iMsvEntries)
       
   103 		{
       
   104 		iMsvEntries->ResetAndDestroy();	
       
   105 		iMsvEntries->Close();	
       
   106 		}
       
   107 	delete iMsvEntries;
       
   108 	iMsvEntries = NULL;
       
   109 	iMsvTmpEntries.Close();
       
   110 	iMsvEntryFreePool = NULL;
       
   111 	}
       
   112 
       
   113 
       
   114 
       
   115 /**
       
   116  * Instance()
       
   117  *
       
   118  * The function returns already created instance of
       
   119  * this class to the caller. To create a new instance
       
   120  * the caller should call CreateL(). If an instance of
       
   121  * this object does not already exists, the function 
       
   122  * throws a panic EMsvFreePoolNotCreated in DEBUG mode.
       
   123  */ 
       
   124 CMsvEntryFreePool* CMsvEntryFreePool::Instance()
       
   125 	{
       
   126 	__ASSERT_DEBUG(iMsvEntryFreePool!=NULL, PanicServer(EMsvFreePoolNotCreated));
       
   127 	return iMsvEntryFreePool;
       
   128 	}
       
   129 	
       
   130 	
       
   131 
       
   132 /**
       
   133  * CreateL()
       
   134  *
       
   135  * The only way to create an object of this class.
       
   136  * The function ensures that only one instance of
       
   137  * the object is created. This is a static interface.
       
   138  * The function is made private to ensure that only
       
   139  * friend function can create instance of this class.
       
   140  */ 
       
   141 CMsvEntryFreePool* CMsvEntryFreePool::CreateL(TDblQue<CMsvCacheVisibleFolder>* aEntryCache /*DEFAULT=NULL*/)
       
   142 	{
       
   143 	CMsvEntryFreePool* self = new (ELeave) CMsvEntryFreePool(aEntryCache);
       
   144 	//Push object in to cleanup stack so that it 
       
   145 	// will be handles properly incase of a leave.
       
   146 	CleanupStack::PushL(self);
       
   147 
       
   148 	self->ConstructL();
       
   149 
       
   150 	//Pop from cleanupstack
       
   151 	CleanupStack::Pop(self);
       
   152 	iMsvEntryFreePool = self;
       
   153 	
       
   154 	return self;
       
   155 	}
       
   156 
       
   157 
       
   158 
       
   159 
       
   160 /**
       
   161  * ConstructL()
       
   162  *
       
   163  * The function is called from InstanceL() and used to
       
   164  * initialize the instance of this class. It firsts reads
       
   165  * cache configuration information from msgcache.ini file
       
   166  * and stores them into member variable. It then allocates
       
   167  * creates initial set of entries as described in conf file. 
       
   168  */
       
   169 void CMsvEntryFreePool::ConstructL()
       
   170 	{
       
   171 	// 1. Reading ini file
       
   172 	
       
   173 	// If drive information is not mentioned in the 
       
   174 	// filename, by default the class will check in
       
   175 	// C: drive. If the file is not found in C: it 
       
   176 	// will check in Z: drive as well.
       
   177 	CMsvIniData* iniFile = NULL;
       
   178 	TRAPD(err, iniFile = CMsvIniData::NewL(KMSGINI));
       
   179 	
       
   180 	// If we find the config file, read it. Else assign default values to cache configurations.
       
   181 	if(!err && iniFile)
       
   182 		{
       
   183 		CleanupStack::PushL(iniFile);
       
   184 
       
   185 		// Reading maximum cache size from ini file.
       
   186 		// Initially, iMsvMaximumCacheSize will have cache size in KB which
       
   187 		// will later be converted to number of cache entries possible.
       
   188 		User::LeaveIfError(iniFile->FindVar(KIniMsvMaximumCacheSize, iMsvMaximumCacheSize));
       
   189 
       
   190 		// Reading initial cache size from ini file.
       
   191 		// This is represented in terms of percentage 
       
   192 		// of maximum cache size.
       
   193 		User::LeaveIfError(iniFile->FindVar(KIniMsvInitialCacheCreation, iMsvInitialCacheSize));
       
   194 
       
   195 		// Reading cache increment value from ini file.
       
   196 		// This is represented in terms of percentage 
       
   197 		// of maximum cache size.
       
   198 		User::LeaveIfError(iniFile->FindVar(KIniMsvCacheIncrement, iMsvCacheIncrement));
       
   199 
       
   200 		// Reading threshold value from ini file
       
   201 		// This is represented in terms of percentage
       
   202 		// of maximum cache size. 
       
   203 		User::LeaveIfError(iniFile->FindVar(KIniMsvCacheThreshold, iMsvCacheThreshold));
       
   204 
       
   205 		// Reading Search Sort Cache value in percentage from ini file
       
   206 		// This is represented in terms of percentage
       
   207 		// of maximum cache size.
       
   208 		User::LeaveIfError(iniFile->FindVar(KIniMsvSearchSortCache, iMsvSearchSortCache));
       
   209 
       
   210 		CleanupStack::PopAndDestroy(iniFile);
       
   211 		}
       
   212 
       
   213 	// Performing consistency check.
       
   214 	if(NULL == iMsvMaximumCacheSize)
       
   215 		{
       
   216 		iMsvMaximumCacheSize = DEFAULT_MAXIMUM_CACHE_SIZE;
       
   217 		}
       
   218 	if((iMsvInitialCacheSize > PERCENTAGE_VALUE) || (NULL == iMsvInitialCacheSize))
       
   219 		{
       
   220 		iMsvInitialCacheSize = DEFAULT_INITIAL_CACHE_SIZE_IN_PERCENTAGE;
       
   221 		}
       
   222 	if((iMsvCacheIncrement > PERCENTAGE_VALUE) || (NULL == iMsvCacheIncrement))
       
   223 		{
       
   224 		iMsvCacheIncrement = DEFAULT_CACHE_INCREMENT_SIZE_IN_PERCENTAGE;
       
   225 		}
       
   226 	if((iMsvCacheThreshold > PERCENTAGE_VALUE) || (NULL == iMsvCacheThreshold))
       
   227 		{
       
   228 		iMsvCacheThreshold = DEFAULT_CACHE_THRESHOLD_IN_PERCENTAGE;
       
   229 		}
       
   230 	
       
   231 	//Determine maximum number of cache entries possible.
       
   232 	iMsvMaxEntries = ConvertMemToEntry(iMsvMaximumCacheSize * 1024);
       
   233 	
       
   234 	// Approximate number of entries to be created when server starts.
       
   235 	TInt initialNumberOfEntries = (iMsvInitialCacheSize * iMsvMaxEntries) / 100;
       
   236 
       
   237 	// Since allocation is done in specific increment size, it is best
       
   238 	// to give the granularity as the increment count (not percentage here).
       
   239 	iMsvEntries = new(ELeave) RPointerArray<CMsvCacheEntry>((iMsvCacheIncrement * iMsvMaxEntries) / 100);
       
   240 
       
   241 	// Create the initial number of cache entries.
       
   242 	// iMsvCacheNumberOfEntriesCreated will store
       
   243 	// number of CMsvCacheEntry created so far.
       
   244 	for (iMsvCacheNumberOfEntriesCreated = 0; iMsvCacheNumberOfEntriesCreated < initialNumberOfEntries ; iMsvCacheNumberOfEntriesCreated++)
       
   245 		{
       
   246 		iMsvEntries->AppendL(CMsvCacheEntry::NewL());
       
   247 		}
       
   248 	
       
   249 	// Percentage of allocated memory utilized so far.
       
   250 	iMsvPercentageAllocated = iMsvInitialCacheSize;
       
   251 	
       
   252 	}
       
   253 
       
   254 
       
   255 
       
   256 void CMsvEntryFreePool::SetEssentialParam(TDblQue<CMsvCacheVisibleFolder>* aEntryCache, CMsvIndexAdapter* aAdapterObj)
       
   257 	{
       
   258 	iEntryCache = aEntryCache;
       
   259 	iAdapter = aAdapterObj;
       
   260 	}
       
   261 
       
   262 
       
   263 
       
   264 /**
       
   265  * ConvertMemToEntry()
       
   266  * @param aMem: Memory size in bytes.
       
   267  * @return TInt: the number of entries that the free pool can have
       
   268  *				 given a memory size in bytes.
       
   269  *
       
   270  * The function calculates the number of cache entries possible in
       
   271  * the free pool given the memory size.
       
   272  */
       
   273 TInt CMsvEntryFreePool::ConvertMemToEntry(TInt aMem)
       
   274 	{
       
   275 	//This calculation is based on the fact that not all cache entries will have
       
   276 	//children as most are leaf nodes. Our assumption is that 20% of the entries
       
   277 	//will have an RArray, i.e. have children. The following formula determines
       
   278 	//maximum number of entries that the cache can have as:
       
   279 	//		sizeof(CMsvCacheEntry) = 120 bytes;
       
   280 	//		sizeof(RArray<TMsvId>) = 36 bytes;
       
   281 	//		sizeof(RArray<TMsvId>*) = 4 bytes;
       
   282 	//	=>	multiplying factor = (80*120 + 20*156)/(120*100) = 1.06
       
   283 	return ( (aMem) / (1.06*sizeof(CMsvCacheEntry)) );	 
       
   284 	}
       
   285 
       
   286 
       
   287 
       
   288 /**
       
   289  * Destroy()
       
   290  * @param CMsvEntryFreePool: The object to be destroyed.
       
   291  *
       
   292  * Only way to destroy an object of this class in debug 
       
   293  * mode. The functions raises a panic when amount of
       
   294  * cache entry created so far is not same as amount of 
       
   295  * entry the object currently holds. The function is 
       
   296  * declared private so that only friend class can call this.
       
   297  *
       
   298  * In release mode destructor should be called directly.
       
   299  */
       
   300 #ifdef _DEBUG
       
   301 
       
   302 void CMsvEntryFreePool::Destroy(CMsvEntryFreePool* aFreePoolInstance)
       
   303 	{
       
   304 	if(NULL==aFreePoolInstance)
       
   305 		return;
       
   306 	
       
   307 	if(aFreePoolInstance->iMsvTmpEntries.Count())
       
   308 		{
       
   309 		aFreePoolInstance->CommitTransaction();
       
   310 		}
       
   311 	
       
   312 	// Check if the number of entries created so far is same
       
   313 	// as amount of entry currently present with freepool (iMsvEntries).	
       
   314 	__ASSERT_DEBUG(aFreePoolInstance->iMsvCacheNumberOfEntriesCreated==aFreePoolInstance->iMsvEntries->Count(), User::Invariant());
       
   315 	
       
   316 	delete aFreePoolInstance;
       
   317 	}
       
   318 	
       
   319 #endif
       
   320 
       
   321 
       
   322 	
       
   323 /**
       
   324  * EntryL()
       
   325  * @param None.
       
   326  * @return CMsvCacheEntry*: An unused CMsvCacheEntry.
       
   327  *
       
   328  * Returns one unused entry from the freepool. If
       
   329  * freepool is empty, it checks if a new entry can 
       
   330  * be allocated and returned. If amount of new entry
       
   331  * created equals the maximum allowed limit (as set
       
   332  * by the licencees in .ini file), the function calls
       
   333  * SwapEntries to swap few entries from cache.
       
   334  * If no entries can be allocated or swapped, it
       
   335  * leaves with KErrNoMemory.
       
   336  */
       
   337 CMsvCacheEntry* CMsvEntryFreePool::EntryL()
       
   338 	{
       
   339 	// Number of entries available in freepool.
       
   340 	TInt count = iMsvEntries->Count();
       
   341 	CMsvCacheEntry* entry = NULL;
       
   342 	
       
   343 	// Is entry available in freepool?
       
   344 	if (0 < count)
       
   345 		{		
       
   346 		// Just return the last entry.
       
   347 		entry = (*iMsvEntries)[--count];
       
   348 		iMsvEntries->Remove(count);
       
   349 		return entry;
       
   350 		}
       
   351 	else
       
   352 		{
       
   353 		// Can we still allocate fresh memory?
       
   354 		if(iMsvMaxEntries > iMsvCacheNumberOfEntriesCreated)
       
   355 			{
       
   356 			++iMsvCacheNumberOfEntriesCreated;
       
   357 			return CMsvCacheEntry::NewL();
       
   358 			}
       
   359 		//Otherwise swap out BLOCK_SIZE entries to free up space.
       
   360 		//Form an entry from this memory and return it.
       
   361 		else
       
   362 			{
       
   363 			SwapEntriesL(BLOCK_SIZE);
       
   364 			count = iMsvEntries->Count();
       
   365 			if(count)
       
   366 				{	
       
   367 				entry = (*iMsvEntries)[--count];
       
   368 				iMsvEntries->Remove(count);
       
   369 				return entry;
       
   370 				}
       
   371 			else
       
   372 				{
       
   373 				++iMsvCacheNumberOfEntriesCreated;
       
   374 				return CMsvCacheEntry::NewL();
       
   375 				}
       
   376 			}
       
   377 		}
       
   378 	}
       
   379 
       
   380 
       
   381 
       
   382 /**
       
   383  * ReleaseEntry()
       
   384  * @param CMsvCacheEntry* : Entry to be release to freepool.
       
   385  * @return None.
       
   386  * 
       
   387  * The function resets and appends the passed 
       
   388  * entry to freepool so that it can be reused.
       
   389  */
       
   390 void CMsvEntryFreePool::ReleaseEntry(CMsvCacheEntry* aMsvCacheEntry, TBool aBypassTransaction /* DEFAULT=EFalse*/)
       
   391 	{
       
   392 	if( NULL == aMsvCacheEntry )
       
   393 		{
       
   394 		return;
       
   395 		}
       
   396 	
       
   397 	if(isTransactionOpen && (EFalse == aBypassTransaction))
       
   398 		{
       
   399 		iMsvTmpEntries.Append(aMsvCacheEntry);
       
   400 		}
       
   401 	else
       
   402 		{
       
   403 		// 1. Reset the entry data.
       
   404 		aMsvCacheEntry->ResetEntry();
       
   405 	
       
   406 		// 2. Append entry to the freepool.
       
   407 		iMsvEntries->Append(aMsvCacheEntry);
       
   408 		}
       
   409 	}
       
   410 
       
   411 
       
   412 
       
   413 void CMsvEntryFreePool::ReleaseEntryWithoutTransaction(CMsvCacheEntry* aMsvCacheEntry)
       
   414     {
       
   415     if(NULL == aMsvCacheEntry)
       
   416         {
       
   417         return;
       
   418         }
       
   419    
       
   420     aMsvCacheEntry->ResetEntry();
       
   421     TRAPD(Err, iMsvEntries->AppendL(aMsvCacheEntry));
       
   422     if(Err)
       
   423         {
       
   424         delete aMsvCacheEntry;
       
   425         iMsvCacheNumberOfEntriesCreated--;
       
   426         }
       
   427     }
       
   428 
       
   429 
       
   430 
       
   431 
       
   432 
       
   433 /**
       
   434  * ReleaseEntrySet()
       
   435  * @param RPointerArray<CMsvCacheEntry>* : Entry set to be released.
       
   436  * @return None.
       
   437  *
       
   438  * The function resets and appends the passed set
       
   439  * of entries to freepool so that it can be reused.
       
   440  */
       
   441 void CMsvEntryFreePool::ReleaseEntrySet(RPointerArray<CMsvCacheEntry>& aMsvCacheEntryArray)
       
   442 	{
       
   443 	TRAPD(error, DoReleaseEntrySetL(aMsvCacheEntryArray));
       
   444 	if(error)
       
   445 		{
       
   446 		// 1. delete the remaining cache entries from aMsvCacheEntryArray
       
   447 		// 2. reduce appropriate variables in CMsvEntryFreePool
       
   448 		TInt count = aMsvCacheEntryArray.Count();
       
   449 		iMsvCacheNumberOfEntriesCreated -= count;
       
   450 		while(count)
       
   451 			{
       
   452 			// 1. Reset the entry data.
       
   453 			aMsvCacheEntryArray[--count]->ResetEntry();
       
   454 			
       
   455 			// 2. Delete the memory allocated to the cache entry.
       
   456 			delete aMsvCacheEntryArray[count];
       
   457 			aMsvCacheEntryArray.Remove(count);
       
   458 			}		
       
   459 		}
       
   460 	}
       
   461 
       
   462 
       
   463 /**
       
   464  * DoReleaseEntrySetL()
       
   465  * @param RPointerArray<CMsvCacheEntry>* : Entry set to be released.
       
   466  * @return None.
       
   467  *
       
   468  * The function resets and appends the passed set
       
   469  * of entries to freepool so that it can be reused.
       
   470  */
       
   471 void CMsvEntryFreePool::DoReleaseEntrySetL(RPointerArray<CMsvCacheEntry>& aMsvCacheEntryArray)
       
   472 	{
       
   473 	TInt count = aMsvCacheEntryArray.Count();
       
   474 	while ( 0 < count)
       
   475 		{
       
   476 		if(isTransactionOpen)
       
   477 			{
       
   478 			iMsvTmpEntries.AppendL(aMsvCacheEntryArray[--count]);
       
   479 			}
       
   480 		else
       
   481 			{
       
   482 			// 1. Reset the entry data.
       
   483 			aMsvCacheEntryArray[--count]->ResetEntry();
       
   484 
       
   485 #ifdef SYMBIAN_MESSAGESTORE_UNIT_TESTCODE
       
   486 			if(iReleaseError)
       
   487 				{
       
   488 				if(iReleaseErrorOffset == count)
       
   489 					{
       
   490 					iReleaseError = EFalse;
       
   491 					User::Leave(KErrNoMemory); // an arbitrary error purely for testing purpose
       
   492 					}
       
   493 				}
       
   494 #endif
       
   495 			// 2. Add entry to the freepool.
       
   496 			iMsvEntries->AppendL(aMsvCacheEntryArray[count]);
       
   497 			}
       
   498 		
       
   499 		// 3. Remove entry from the input array.
       
   500 		aMsvCacheEntryArray.Remove(count);
       
   501 		}
       
   502 	}
       
   503 
       
   504 
       
   505 
       
   506 /**
       
   507  * 
       
   508  */
       
   509 void CMsvEntryFreePool::RollbackTransaction()
       
   510 	{
       
   511 	TInt count = iMsvTmpEntries.Count();
       
   512 	while(0 < count)
       
   513 		{
       
   514 		if(NULL != iAdapter)
       
   515 			{
       
   516 			TRAP_IGNORE(iAdapter->AddEntryNoVisibleL(iMsvTmpEntries[--count]));
       
   517 			}
       
   518 		}
       
   519 	iMsvTmpEntries.Reset();
       
   520 	isTransactionOpen = EFalse;
       
   521 	}
       
   522 
       
   523 
       
   524 /**
       
   525  * 
       
   526  */
       
   527 void CMsvEntryFreePool::CommitTransaction()
       
   528 	{
       
   529 	TInt count = iMsvTmpEntries.Count();
       
   530 	while(0 < count)
       
   531 		{
       
   532 		iMsvTmpEntries[--count]->ResetEntry();
       
   533 		iMsvEntries->Append(iMsvTmpEntries[count]);
       
   534 		}
       
   535 	iMsvTmpEntries.Reset();
       
   536 	isTransactionOpen = EFalse;
       
   537 	}
       
   538 
       
   539 
       
   540 
       
   541 /**
       
   542  * SwapEntriesL()
       
   543  * @param TInt: number of entries to be swapped out.
       
   544  * @return None.
       
   545  *
       
   546  * Swap a specified amount of entries from cache.
       
   547  * The function is called by GetEntry() when it
       
   548  * cannot return an unused entry since freepool is
       
   549  * empty. 
       
   550  */
       
   551 void CMsvEntryFreePool::SwapEntriesL(TInt aEntriesToSwap)
       
   552 	{
       
   553 	if(!iEntryCache)
       
   554 		{
       
   555 		User::Leave(KErrArgument);
       
   556 		}
       
   557 	CMsvCacheVisibleFolder* folderNode = NULL;
       
   558 	TDblQueIter<CMsvCacheVisibleFolder> dqIter(*iEntryCache);
       
   559 
       
   560     dqIter.SetToLast();
       
   561     TInt entriesReleased = 0;
       
   562     TBool isFolderEmpty;
       
   563         
       
   564     while(	((folderNode = dqIter--) != NULL) &&  (entriesReleased < aEntriesToSwap) 
       
   565 #if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)           
       
   566    	//We do not swap out Local service and root folder node.
       
   567            &&  (KMsvLocalServiceIndexEntryId) != UnmaskTMsvId(folderNode->GetFolderId())
       
   568            &&  (KMsvRootIndexEntryId != folderNode->GetFolderId())
       
   569 #else 
       
   570            &&  (KMsvLocalServiceIndexEntryId) != folderNode->GetFolderId()
       
   571            &&  (KMsvRootIndexEntryId != folderNode->GetFolderId())
       
   572 #endif
       
   573 	  	 )
       
   574         {
       
   575         isFolderEmpty = EFalse;
       
   576         //Attempt to reclaim aEntriesToSwap from a single folder.
       
   577         //The number of entries swapped out can be more than aEntriesToSwap.
       
   578        	entriesReleased += folderNode->ReleaseBlocks((aEntriesToSwap - entriesReleased), isFolderEmpty);
       
   579 		#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)  
       
   580 			TMsvId folderId = UnmaskTMsvId(folderNode->GetFolderId());
       
   581 		#else
       
   582 			TMsvId folderId = folderNode->GetFolderId();
       
   583 		#endif
       
   584 
       
   585 		if(isFolderEmpty && !folderNode->GetChildrenFromVisibleFolder() && folderId > KMsvDeletedEntryFolderEntryId )
       
   586         	{
       
   587         	folderNode->iDlink.Deque();
       
   588         	delete folderNode;
       
   589         	break;
       
   590         	}
       
   591         }
       
   592     }
       
   593 
       
   594 
       
   595 
       
   596 
       
   597 /**
       
   598  * IsAllocationRequiredL()
       
   599  * @param None.
       
   600  * @return TBool: ETrue if the free pool has reached its threshold,
       
   601  *				  EFalse if otherwise.
       
   602  *
       
   603  * The function return ETrue if the free pool has reached its 
       
   604  * threshold and EFalse if otherwise.
       
   605  */
       
   606 TBool CMsvEntryFreePool::IsAllocationRequiredL()
       
   607 	{
       
   608 	// Size of actual cache data structure.
       
   609     iMsvCacheSize = CacheSizeL();
       
   610     
       
   611     // Total cache size includes the size of freepool as well.
       
   612     TInt totalCacheSize = iMsvCacheSize + iMsvEntries->Count()*sizeof(CMsvCacheEntry);
       
   613     
       
   614     //Check if the size of the folder list exceeds or equals the threshold.
       
   615     //If all of the cache memory has been used up, checking is done against
       
   616     //the secondary threshold value.
       
   617     if( PERCENTAGE_VALUE == iMsvPercentageAllocated )
       
   618     	{	
       
   619     	if(iMsvCacheSize > (totalCacheSize * CACHE_THRESHOLD_AFTER_FULL_CACHE/100))
       
   620     		{
       
   621     		return ETrue;
       
   622     		}
       
   623     	else
       
   624 	    	{
       
   625     		return EFalse;
       
   626     		}
       
   627     	}
       
   628     else
       
   629     	{
       
   630 		if(iMsvCacheSize > (totalCacheSize * iMsvCacheThreshold/100))
       
   631     		{
       
   632     		return ETrue;
       
   633     		}
       
   634     	else
       
   635 	    	{
       
   636     		return EFalse;
       
   637     		}
       
   638     	}
       
   639 	}
       
   640 
       
   641 
       
   642 
       
   643 /**
       
   644  * CacheSizeL()
       
   645  * @param None.
       
   646  * @return TInt: the size of the cache data structure in bytes.
       
   647  *
       
   648  * The function returns the size of the cache data structure in bytes, 
       
   649  * excluding the memory occupied by the free entries in the freepool.
       
   650  */
       
   651 TInt CMsvEntryFreePool::CacheSizeL()
       
   652 	{
       
   653 	if(!iEntryCache)
       
   654 		{
       
   655 		User::Leave(KErrArgument);
       
   656 		}
       
   657 	CMsvCacheVisibleFolder* folderNode = NULL;
       
   658 	TDblQueIter<CMsvCacheVisibleFolder> dqIter(*iEntryCache);
       
   659  	TInt cacheSize = 0;
       
   660  	TInt folderCount = 0;
       
   661 	
       
   662     //Calculate the size of the whole folder list structure.
       
   663     //This includes the size required for the data structures,
       
   664     // Eg: index table, block of entries etc.
       
   665     dqIter.SetToFirst();
       
   666     while ((folderNode = dqIter++) != NULL)
       
   667         {
       
   668         ++folderCount;
       
   669     	RPointerArray<CMsvCacheIndexTableEntry> *indexTable = folderNode->GetIndexTableEntry();
       
   670     	//Number of blocks in the indextable, i.e. number of indextable entries.
       
   671     	TInt count = indexTable->Count();
       
   672     	for(TInt index = 0; index < count; ++index)
       
   673     		{
       
   674     		TInt entryCount = (*indexTable)[index]->Size();
       
   675     		cacheSize += entryCount * (sizeof(CMsvCacheEntry) * 1.06);
       
   676     		//Include the size of the details and description buffers of a cache entry.
       
   677     		//Size of buffers and members of TMsvEntry is the same.
       
   678     		//Description and details each have standard size of 15.
       
   679     		cacheSize += (2*15) * entryCount;
       
   680     		}
       
   681     	//Size of data structure for the blocks.
       
   682     	cacheSize += count * sizeof(CMsvCacheIndexTableEntry);
       
   683     	}
       
   684     //Size of the data structure for index tables.
       
   685     cacheSize += folderCount * sizeof(CMsvCacheVisibleFolder); //bytes
       
   686     return cacheSize;
       
   687 	}
       
   688 
       
   689 
       
   690 
       
   691 /**
       
   692  * AllocateMemoryL()
       
   693  * @param None.
       
   694  * @return None.
       
   695  *
       
   696  * The function expands the cache free pool when it has reached its threshold.
       
   697  * If all of the memory has not been used up yet, it allocates the entries as per
       
   698  * the next increment. It allocates memory again if threshold is still being exceeded.
       
   699  * Swapping might be performed to maintain the threshold.
       
   700  * If all of the memory has been used up, it swaps out (100-iMsvCacheThreshold)% entries
       
   701  * from cache.
       
   702  */
       
   703 void CMsvEntryFreePool::AllocateMemoryL()
       
   704 	{
       
   705 	//Total cache size includes the size of freepool as well.
       
   706 	TInt totalCacheSize = iMsvCacheSize + iMsvEntries->Count()*sizeof(CMsvCacheEntry);
       
   707 	
       
   708 	// Check if entire memory is not yet allocated to cache.
       
   709 	if(PERCENTAGE_VALUE > iMsvPercentageAllocated)
       
   710 		{
       
   711 		//Yes, it has not been used up. Calculate the percentage allocation done till now.
       
   712 		TInt actualPercentage = (totalCacheSize * 100/1024)/iMsvMaximumCacheSize;
       
   713 		while(actualPercentage >= iMsvPercentageAllocated && iMsvPercentageAllocated < PERCENTAGE_VALUE)
       
   714 			{
       
   715 			iMsvPercentageAllocated += iMsvCacheIncrement;
       
   716 			}
       
   717 		if(PERCENTAGE_VALUE < iMsvPercentageAllocated)
       
   718 			{
       
   719 			iMsvPercentageAllocated = PERCENTAGE_VALUE;
       
   720 			}
       
   721 		
       
   722 		//Calculate how much memory has to be allocated in terms of cache entries.
       
   723 		TInt memoryDiff = iMsvMaximumCacheSize*1024*(iMsvPercentageAllocated - actualPercentage)/100;
       
   724 		if(memoryDiff > 0)
       
   725 			{
       
   726 			TInt entriesToCreate = ConvertMemToEntry(memoryDiff); 
       
   727 			for(TInt index = 0; index < entriesToCreate; ++index)
       
   728 				{
       
   729 				iMsvEntries->AppendL(CMsvCacheEntry::NewL());
       
   730 				++iMsvCacheNumberOfEntriesCreated;
       
   731 				}	
       
   732 			}
       
   733 		//If the cache data structure size still exceeds the threshold go for 
       
   734 		//the next increment allocation.
       
   735 		totalCacheSize = iMsvCacheSize + iMsvEntries->Count()*sizeof(CMsvCacheEntry);
       
   736 		if( (totalCacheSize * iMsvCacheThreshold)/100 < iMsvCacheSize )
       
   737 			{
       
   738 			//If all of the memory has been used up now, swap out entries.
       
   739 			if( PERCENTAGE_VALUE == iMsvPercentageAllocated )
       
   740 				{
       
   741 				SwapEntriesL(PERCENTAGE_TO_SWAP_OUT*iMsvMaxEntries/100);					
       
   742 				}
       
   743 			//Otherwise calculate the number of entries in the increment and allocate.
       
   744 			else
       
   745 				{
       
   746 				TInt previousPercent = iMsvPercentageAllocated;
       
   747 				iMsvPercentageAllocated += iMsvCacheIncrement;
       
   748 				if(PERCENTAGE_VALUE < iMsvPercentageAllocated)
       
   749 					{
       
   750 					iMsvPercentageAllocated = PERCENTAGE_VALUE;
       
   751 					}
       
   752 				memoryDiff = iMsvMaximumCacheSize*1024*(iMsvPercentageAllocated - previousPercent)/100;
       
   753 				TInt entriesToCreate = ConvertMemToEntry(memoryDiff); 
       
   754 				for(TInt index = 0; index < entriesToCreate; ++index)
       
   755 					{
       
   756 					iMsvEntries->AppendL(CMsvCacheEntry::NewL());
       
   757 					++iMsvCacheNumberOfEntriesCreated;
       
   758 					}		
       
   759 				}
       
   760 			}		
       
   761 		}	
       
   762 	else
       
   763 		{
       
   764 		//All of the cache memory has been used. Go for swapping out of entries from the 
       
   765 		//cache data structure to free up memory.
       
   766 		SwapEntriesL(PERCENTAGE_TO_SWAP_OUT*iMsvMaxEntries/100);
       
   767 		}	
       
   768 		
       
   769 	//Calculate the number of entries that can be formed from the remaining memory.
       
   770 	if( PERCENTAGE_VALUE == iMsvPercentageAllocated )
       
   771 		{
       
   772 		iMsvMaxEntries = iMsvCacheNumberOfEntriesCreated;
       
   773 		}
       
   774 	else
       
   775 		{
       
   776 		iMsvMaxEntries = iMsvCacheNumberOfEntriesCreated + ConvertMemToEntry((iMsvMaximumCacheSize * 1024) * (100-iMsvPercentageAllocated)/100);
       
   777 		}
       
   778 	}
       
   779 	
       
   780 
       
   781 
       
   782 /**
       
   783  * FlushExcessMemory()
       
   784  */
       
   785 void CMsvEntryFreePool::FlushExcessMemory()
       
   786 	{
       
   787 	TInt count = iUsedCacheEntries.Count();
       
   788 	if(count)
       
   789 		{
       
   790 		CMsvCacheEntry *entry = NULL;
       
   791 		while(count)
       
   792 			{
       
   793 			entry = iUsedCacheEntries[0];
       
   794 			iUsedCacheEntries.Remove(0);
       
   795 			if(iMsvMaxEntries < iMsvCacheNumberOfEntriesCreated)
       
   796 				{
       
   797 				delete entry;
       
   798 				iMsvCacheNumberOfEntriesCreated--;
       
   799 				}
       
   800 			else
       
   801 				{
       
   802 				entry->ResetEntry();
       
   803 				iMsvEntries->Append(entry);
       
   804 				}
       
   805 			--count;
       
   806 			}
       
   807 		iUsedCacheEntries.Reset();
       
   808 		}
       
   809 	}
       
   810 	
       
   811 	
       
   812 	
       
   813 void CMsvEntryFreePool::RoutineFreePoolCleanUpL()
       
   814 	{
       
   815 	FlushExcessMemory();
       
   816 	TInt excessMemory = ExcessMemoryAllocated();
       
   817 	if(excessMemory)
       
   818 		{
       
   819 		SwapEntriesL(excessMemory);
       
   820 		}	
       
   821 	}