messagingfw/msgsrvnstore/server/src/msvcacheindextableentry.Cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 18 Jan 2010 20:36:02 +0200
changeset 0 8e480a14352b
child 36 e7635922c074
permissions -rw-r--r--
Revision: 201001 Kit: 201003

// 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:
// CMSVCACHEINDEXTABLEENTRY.CPP
// HEADER FILES
// 
//

#include "msvcacheindextableentry.h"
#include "msventryfreepool.h"
#include "msvcacheentry.h"

#if (defined SYMBIAN_MSGS_ENHANCED_REMOVABLE_MEDIA_SUPPORT)	
	#include "msvindexadapter.h"
#endif

/**
 * FUNCTION DEFINITION
 */
 

//****************************
//CMsvCacheIndexTableEntry
//****************************

/**
 * NewL()
 * @param None.
 * @return The newly created index table entry
 * 
 * It returns an instance of the CMsvCacheIndexTableEntry class, i.e. a newly 
 * constructed index table with no entries in it.
 */
CMsvCacheIndexTableEntry* CMsvCacheIndexTableEntry::NewL()
	{
	CMsvCacheIndexTableEntry *self = new(ELeave) CMsvCacheIndexTableEntry();
	return self;
	}


/**
 * NewL()
 * @param CMsvCacheEntry& : a new cache entry
 * @return The newly created index table entry
 * 
 * It returns an instance of the CMsvCacheIndexTableEntry class with the passed entry
 * added.
 */
CMsvCacheIndexTableEntry* CMsvCacheIndexTableEntry::NewL(CMsvCacheEntry*& aEntry)
	{
	CMsvCacheIndexTableEntry *self = CMsvCacheIndexTableEntry::NewLC(aEntry);
	CleanupStack::Pop();
	return self;
	}


/**
 * NewLC()
 * @param CMsvCacheEntry& : a new cache entry
 * @return The newly created index table entry
 * 
 * It returns an instance of the CMsvCacheIndexTableEntry class 
 * with the passed entry added. It leaves the object into cleanup stack.
 */
CMsvCacheIndexTableEntry* CMsvCacheIndexTableEntry::NewLC(CMsvCacheEntry*& aEntry)
	{
	CMsvCacheIndexTableEntry *self = new(ELeave) CMsvCacheIndexTableEntry();
	CleanupStack::PushL(self);
	self->AddEntryL(aEntry);
	return self;
	}




/**
 * NewL()
 * @param RPointerArrayCMsvCacheEntry>& : RPointerArray reference to child entries
 * @return The newly created index table entry
 * 
 * It returns an instance of the CMsvCacheIndexTableEntry class filled with child
 * entries.
 */
CMsvCacheIndexTableEntry* CMsvCacheIndexTableEntry::NewL(RPointerArray<CMsvCacheEntry>& aEntries, TInt aInitIndex /*(DEFALUT=0)*/, TInt aCount /* DEFAULT = -1*/)
	{
	CMsvCacheIndexTableEntry *self = CMsvCacheIndexTableEntry::NewLC(aEntries, aInitIndex, aCount);
	CleanupStack::Pop();
	return self;
	}




/**
 * NewLC()
 * @param RPointerArrayCMsvCacheEntry>& : RPointerArray reference to child entries
 * @return The newly created index table entry
 * 
 * It returns an instance of the CMsvCacheIndexTableEntry class filled with child
 * entries. It leaves the object into cleanup stack.
 */
CMsvCacheIndexTableEntry* CMsvCacheIndexTableEntry::NewLC(RPointerArray<CMsvCacheEntry>& aEntries, TInt aInitIndex /*(DEFALUT=0)*/, TInt aCount /* DEFAULT = -1*/)
	{
	CMsvCacheIndexTableEntry *self = new(ELeave) CMsvCacheIndexTableEntry();
	CleanupStack::PushL(self);
	self->AddEntrySetL(aEntries, aInitIndex, aCount);
	return self;
	}




/**
 * CMsvCacheIndexTableEntry()
 * @param None.
 * @return None.
 * 
 * Constructor
 */
CMsvCacheIndexTableEntry::CMsvCacheIndexTableEntry()
:iMinMsvId(0), iMaxMsvId(0), iFlags(EMsvCacheIndexTableClearFlag)
	{
	iTimeStamp.HomeTime(); //set the timestamp to number of seconds since Epoc.
	iBlockPtr = NULL;
	}


/**
 * ~CMsvCacheIndexTableEntry()
 * @param None.
 * @return None.
 * 
 * Destructor - releases the block to the cache free pool and sets it to NULL.
 */
CMsvCacheIndexTableEntry::~CMsvCacheIndexTableEntry()
	{
	//destructor should delete everything no matter if entries are locked or not
	ReleaseBlock(ETrue);
	}


/**
 * AddEntryL()
 * @param CMsvCacheEntry& : reference to the CMsvCacheEntry to be added.
 * @return None.
 * 
 * The function adds an entry into the index table. The entity who passes the entry
 * to the function will give up ownership of the same and hence cannot modify or 
 * delete it.
 * 1. If the block is NULL, it creates a new one and appends the entry to the block
 *    and accordingly sets the TMsvId ranges.
 * 2. If block is not NULL, then append the entry to it.
 * 	2.1 If the entry already exists in the block then release the old entry from the block and
 *		append the new one.
 * 	2.2 If the entry fits only at the end of the last block then we need to change
 *      the iMaxMsvid.
 *      If the indextable has not been created and if the folder has just one block, and this block contains
 * 		random entries, then we may need to set the iMinMsvId.
 */
void CMsvCacheIndexTableEntry::AddEntryL(CMsvCacheEntry*& aEntry, TBool aReplace /* DEFAULT = EFalse*/)
	{
	TMsvId entryId = aEntry->GetId();
	//	1. If the block is NULL, it creates a new one and appends the entry to the block
	//     and accordingly sets the TMsvId ranges.
	if(NULL == iBlockPtr)
		{
		iBlockPtr = new(ELeave) RPointerArray<CMsvCacheEntry>;
		iBlockPtr->AppendL(aEntry);
		SetMinMsvIdRange(entryId);
		SetMaxMsvIdRange(entryId);
		} //if(NULL == iBlockPtr)
	
	//	2. If block is not NULL:
	else
		{
		// 2.1 If the entry already exists in the block then release the old entry from the
		//	   block and append the new one.
		TInt blockSize = Size();
		for(TInt blockIndex = 0; blockIndex < blockSize; ++blockIndex)
			{
			if((*iBlockPtr)[blockIndex]->GetId() == aEntry->GetId())
				{
				if(!aReplace)
					{
					CMsvEntryFreePool::Instance()->ReleaseEntry(aEntry);
					aEntry = (*iBlockPtr)[blockIndex];
					return;
					}
				CMsvEntryFreePool::Instance()->ReleaseEntry((*iBlockPtr)[blockIndex]);
				iBlockPtr->Remove(blockIndex);
				iBlockPtr->Insert(aEntry, blockIndex);
				return;
				}
			}
		iBlockPtr->AppendL(aEntry);
		
		// 2.2 If the entry fits only at the end of the last block then we need to
		//     change the iMaxMsvid.
		//     If the indextable has not been created and if the folder has just
		//     one block, and this block contains random entries, then we may need to 
		//     set the iMinMsvId.
		if(entryId > iMaxMsvId)
			{
			SetMaxMsvIdRange(entryId);
			}
			
		if(entryId < iMinMsvId)
			{
			SetMinMsvIdRange(entryId);
			}
		} //else
	iTimeStamp.HomeTime();
	}




/**
 * AddEntrySetL()
 * @param RPointerArray<CMsvCacheEntry>& : reference to the new entry set to be added.
 * 										   These entries can either be immediate children
 * 										   or non-immediate children, but not both.
 * @param TInt aInitIndex : Start index of the entry to be added in the entryList.
 * @param TInt aCount     : Number of entries that should be added.
 * @return None.
 * 
 * The function adds a set of entries to the index table. The caller who passes the 
 * array of entries to the function will give up ownership of the entries in the array.
 * 1. When the block is NULL:
 * 	1.1 If children of a non-immediate folder are present in the array then set the 
 *      grandchildren and dirty flags.
 * 	1.2 If there aren't, then clear the above two flags.
 * 	1.3 Assign the new entry set to the block, but reset the passed set so that
 *	   the caller cannot modify or delete the cache entries.
 * 2. When the block is not NULL:
 *  2.1 If children of a non-immediate folder are present in the array then
 *	    set the grandchildren flag and simply append entries to the block.
 *  2.2 If there aren't, append entries avoiding duplication.
 * 		2.2.1 Search for each entry that is present in the current block in the
 *			  new set passed. If the entry is present then release it from the
 *			  current block. If not then append to the new set.
 * 		2.2.2 All entries are now in the passed array. Reset the current block,
 *			  allocate space for it and copy the entries to it. Also reset the 
 *			  passed array so that callers do not have access to the cache
 *			  entries after the addition.
 * 3. Calculate and set the maximum and minimum TMsvId ranges in the newly added set.
 */
void CMsvCacheIndexTableEntry::AddEntrySetL(RPointerArray<CMsvCacheEntry>& aEntries, TInt aInitIndex /*(DEFAULT=0)*/, TInt aCount /* DEFAULT=-1 */)
	{
	// Add all entries if aCount is -1.
	TInt arrSize = aEntries.Count();
	if(-1 == aCount)
		{
		aCount = arrSize;
		}
	if(aInitIndex < 0 || aInitIndex >= arrSize)
		{
		return;
		}
	
	// 1. When the block is NULL:
	if(NULL == iBlockPtr)
		{
		//     Assign the new entry set to the block, but reset the passed set so that
		//	   the caller cannot modify or delete the cache entries.
		//	   Update the ranges of the block.
		
		iBlockPtr = new(ELeave) RPointerArray<CMsvCacheEntry>;
		for(TInt listIndex = 0; (listIndex < aCount) && (arrSize > listIndex+aInitIndex); ++listIndex)
			{
			iBlockPtr->AppendL(aEntries[listIndex+aInitIndex]);
			}
		
		} //if(NULL == iBlockPtr)
	
	// 2. When the block is not NULL append the entries. If there is a duplicate entry,
	//	  discard the new entry.
	else
		{
		TBool entryFound = EFalse;
		TInt blockSize = Size();
		for(TInt listCount = 0; (listCount < aCount) && (arrSize > listCount+aInitIndex); ++listCount)
			{
			entryFound = EFalse;
			for(TInt blockIndex = 0; blockIndex < blockSize; ++blockIndex)
				{
				if(aEntries[listCount+aInitIndex]->GetId() == (*iBlockPtr)[blockIndex]->GetId())
					{
					CMsvEntryFreePool::Instance()->ReleaseEntry(aEntries[listCount+aInitIndex]);
					aEntries.Remove(listCount+aInitIndex);
					aEntries.Insert((*iBlockPtr)[blockIndex], listCount+aInitIndex);
					entryFound = ETrue;
					break;
					}
				}   //for()
			if(!entryFound)
				{
				iBlockPtr->AppendL(aEntries[listCount+aInitIndex]);
				}			
			}   //for()
		} //else
	iTimeStamp.HomeTime();
	}
	
	


/**
 * GetEntry()
 * @param TMsvId : the TMsvId of the entry to be fetched.
 * @param CMsvCacheEntry*& : output parameter for the entry.
 * @return TBool.
 * 
 * The function fetches the entry with the specified TMsvId.
 * 1. If the block is NULL, there is no entry that can be fetched. Return EFalse.
 * 2. Iterate through the block searching for the TMsvId and return ETrue for a hit
 * 3. Return EFalse if the entry is not present in the block.
 */
TBool CMsvCacheIndexTableEntry::GetEntry(TMsvId aId, CMsvCacheEntry*& aEntry)
	{
	// 1. If the block is NULL, there is no entry that can be fetched. Return EFalse.
	if(NULL == iBlockPtr)
		{
		aEntry = NULL;
		return EFalse;
		}
	
	//	2. Iterate through the block searching for the TMsvId and return ETrue for a hit.
	TInt blockSize = Size();
	for(TInt index = 0 ; index < blockSize ; ++index)
		{
		if((*iBlockPtr)[index]->GetId() ==  aId)
			{
			aEntry = (*iBlockPtr)[index];
			iTimeStamp.HomeTime();
			return ETrue;
			}
		} //for
	
	//	3. Return EFalse if the entry is not present in the block.
	return EFalse;
	}


/**
 * GetChildrenL()
 * @param TMsvId : TMsvId of the parent entry of the entries to be fetched.
 * @param RPointerArray<CMsvCacheEntry>*& : output parameter for the entries to be
 *        fetched.
 * @return None.
 * 
 * The function fetches a set of entries with the specified parent TMsvId.
 * 1. Check if there are grandchildren present in the block.
 * 	1.1. If yes, then fetch only those entries with parent Id as aParentId.
 * 		 If the array of entries is NULL, then allocate space for it.
 * 	1.2. If not, then return a copy of the whole block.
 */
void CMsvCacheIndexTableEntry::GetChildrenL(TMsvId aParentId, RPointerArray<CMsvCacheEntry>& aEntries) /*const*/
	{ 
	// 1. Check if there are grandchildren present in the block.
	if(IsGrandChildPresent())
		{
		// 1.1 If yes, then fetch only those entries with parent Id as aParentId.
		//       If the array of entries is NULL, then allocate space for it.
		TInt blockSize = Size();
		for(TInt index = 0 ; index < blockSize ; ++index)
			{
			if((*iBlockPtr)[index]->Entry().Parent() == aParentId)
				{
				aEntries.AppendL((*iBlockPtr)[index]);
				}
			}
		} //if(IsGrandChildPresent())
	
	else
		{
		// 1.2 If not, then return a copy of the whole block.
		TInt blockSize = Size();
		for(TInt index = 0 ; index < blockSize ; ++index)
			{
			aEntries.AppendL((*iBlockPtr)[index]);
			}
		} //else
	iTimeStamp.HomeTime();
	}
	

/**
 * DeleteEntryL()
 * @param TMsvId : the TMsvId of the entry to be deleted.
 * @param aParentIdOfEntry
 * @param aForceDelete TBool, it indicates whether the entry needs to be locked while deleting.
 * @return None.
 * 
 * The function deletes an entry from the cache releasing the entry to the cache free
 * pool. The function is called when the entry is being deleted from both the DB and
 * cache.
 * 1. Return if the block is NULL.
 * 2. Iterate through the block searching for the TMsvId.
 *	2.1 If the entry exists, remove it and release to the free pool. Deletion
 *		 is possible only if the entry is locked in the cache, otherwise the function
 * 		 returns KErrAccessDenied.
 * 		 2.1.1 If the entry deleted was the last entry in the block, delete the
 *		        block.
 * 3. Leave with KErrNotFound if the entry does not exist in the block.	
 */
void CMsvCacheIndexTableEntry::DeleteEntryL(TMsvId aId, TMsvId& aParentIdOfEntry /*DEFAULT = NULL*/, TBool aForceDelete /*DEFAULT=EFalse*/)
	{ 
	// 1. Return if the block is NULL.
	if(NULL == iBlockPtr)
		{
		User::Leave(KErrNotFound);
		}
	
	//	2. Iterate through the block searching for the TMsvId.
	TInt blockSize = Size();
	for(TInt index = 0 ; index < blockSize ; ++index)
		{
		//	2.1 If the entry exists, remove it and release to the free pool. Deletion
		//		 is possible only if the entry is locked in the cache.
		if((*iBlockPtr)[index]->GetId() ==  aId)
			{
			if(aForceDelete || (*iBlockPtr)[index]->IsEntryLocked())
				{
				aParentIdOfEntry = (*iBlockPtr)[index]->Entry().Parent();
				CMsvEntryFreePool::Instance()->ReleaseEntry((*iBlockPtr)[index]);
				iBlockPtr->Remove(index);
				// 2.1.1. If the entry deleted was the last entry in the block,
				//        delete the block.
				if(iBlockPtr->Count() == 0)
					{
					iBlockPtr->Close();
					delete iBlockPtr;
					iBlockPtr = NULL;
					}
				iTimeStamp.HomeTime();
				}
			else
				{
				User::Leave(KErrAccessDenied);
				}
			return;
			}
		} //for
	// 3. Leave with KErrNotFound if the entry does not exist in the block.
	User::Leave(KErrNotFound);
	}


/**
 * ReleaseBlock()
 * @param TBool: internally used flag which is used by destructor to forcibly swap out
 * 				 the block even if entries have been locked.
 * @return TBool: EFalse if block cannot be released as a result of entries having been
 * 				  locked in the cache, ETrue if otherwise.
 * 
 * The function releases a block to the cache free pool.
 * 1. Return EFalse if any of the entries in the block have been locked. Do not
 *    swap out the block to the free pool if so.
 * 2. No entries are locked and/or the block is to be swapped out forcibly.
 *  2.1 Release the entries to the free pool.
 *  2.2 Free the memory allocated to the block itself.
 *  2.3 Set the dirty flag.
 */
TBool CMsvCacheIndexTableEntry::ReleaseBlock(TBool aForceRelease /*DEFAULT = EFalse*/)
	{ 
	if(NULL == iBlockPtr)
		{
		return ETrue;
		}
	// 1. Return EFalse if any of the entries in the block have been locked. Do not
	//	  swap out the block to the free pool if so.
	if(!aForceRelease)
		{
		TInt blockSize = Size();
		for(TInt index = 0; index < blockSize; ++index)
			{
			if(!(*iBlockPtr)[index]->IsEntrySwappable())
				{
				return EFalse;
				}
			}
		}
	
	// 2. No entries are locked and the block can be swapped out safely.
	CMsvEntryFreePool::Instance()->ReleaseEntrySet(*iBlockPtr);
	
	iBlockPtr->Close();
	delete iBlockPtr;
	iBlockPtr = NULL;
	SetDirty();
	return ETrue;
	}


/**
 * CompareOrder()
 * @param const CMsvCacheEntry& : the first operand
 * @param const CMsvCacheEntry& : the second operand
 * @return TInt : the order (-1/0/+1)
 * 
 * The function returns the order for the sort operation.
 */
static TInt CompareOrder(const CMsvCacheEntry& aFirst, const CMsvCacheEntry& aSecond)
	{
	return aFirst.GetId() - aSecond.GetId();
	}


/**
 * SortBlockL()
 * @param None.
 * @return None.
 * 
 * The function is called by a background active object to sort the index table
 * according to TMsvIds of the entries.
 * 1. Sort based on the order in the TLinearOrder package.
 */
void CMsvCacheIndexTableEntry::SortBlock()
	{
	if(iBlockPtr != NULL)
		{
		//	1. Sort based on the order in the TLinearOrder package.
		TLinearOrder<CMsvCacheEntry> order(CompareOrder);
		iBlockPtr->Sort(order);
		}
	}


/**
 * EntryExists()
 * @param TMsvId : the Id of the entry to be checked for existence.
 * @return TBool : success/failure.
 * 
 * The function return EFalse if either the block is NULL or the entry does not exist.
 * ETrue is returned for a hit.
 */
TBool CMsvCacheIndexTableEntry::EntryExists(TMsvId aId) const
 	{
 	if(NULL == iBlockPtr)
		{
		return EFalse;
		}
 	TInt blockSize = Size();
 	for(TInt index = 0 ; index < blockSize ; ++index)
 		{
 		if(aId == (*iBlockPtr)[index]->GetId())
 			{
 			return ETrue;
 			}
 		} //for
 	return EFalse;
 	}


/**
 * UpdateChildMsvIdsL()
 * @param TMsvId : TMsvId of the parent entry.
 * @param TMsvId : TMsvId of the child entry.
 * @param TBool : flag, set to ETrue if aChildId is to be added, and EFalse if it is
 * 				  to be removed from the parent's child array.
 * @return None.
 * 
 * The function updates the child array of the parent entry if it is not NULL.
 * 1. Return if the block is NULL, i.e. the parent is not in the cache.
 * 2. Iterate through the block searching for the parent entry.
 * 	2.1 If the iChildIdArray is not NULL:
 * 		2.1.1 If the child has to be added as a consequence of it being
 *				  added to the cache, then append it to the child array.
 * 		2.1.2 If the child has to be removed as a consequence to the child
 * 		       entry being deleted, then remove it from the child array.
 */
void CMsvCacheIndexTableEntry::UpdateChildMsvIdsL(TMsvId aParentId, TMsvId aChildId, TBool aAdd /*DEFAULT = ETrue*/)
	{
	// 1. Return if the block is NULL, i.e. the parent is not in the cache.
	if(NULL == iBlockPtr)
		{
		return;
		}
	
	//	2. Iterate through the block searching for the parent entry.
	TInt blockSize = Size();
	for(TInt index = 0 ; index < blockSize ; ++index)
		{
		if((*iBlockPtr)[index]->GetId() ==  aParentId)
			{
			RArray<TMsvId>* childArr = (*iBlockPtr)[index]->ChildIdArray();
			// 2.1 If the iChildIdArray is not NULL: i.e GetChildren has been performed
			if(childArr != NULL)
				{
				// 2.1.1 If the child has to be added as a consequence of it being
				//		  added to the cache, then append it to the child array.
				TInt arrSize = childArr->Count();
				if(aAdd)
					{
					TInt index = childArr->Find(aChildId);
					if(index == KErrNotFound)
						{
						childArr->AppendL(aChildId);
						}
					}
				
				// 2.1.2 If the child has to be removed as a consequence to the child
				//        entry being deleted, then remove it from the child array.
				else
					{
					TInt index = childArr->Find(aChildId);
					if(index != KErrNotFound)
						{
						childArr->Remove(index);
						}
					}
				} //if(((*iBlockPtr)[index]->ChildIdArray()) != NULL)
			return;
			} //if((*iBlockPtr)[index]->GetId() ==  aParentId)
		} //for(TInt index = 0 ; index < Size() ; index++)
}


/**
 * UpdateChildMsvIdsL()
 * @param RPointerArray<CMsvCacheEntry>& : array of complete set of child 
 * 										   CMsvCacheEntries sorted by TMsvId.
 * @return None.
 * 
 * The function updates, or creates if necessary, a parent entry's iChildIdArray with
 * the children entries passed to it in the form of a RPointerArray.
 * 1. Return if the block is NULL, i.e. the parent is not in the cache.
 * 2. Otherwise, find the parent sequentially.
 * 	2.1 If the parent is found:
 * 		2.1.1 If the parent already has a iChildIdArray, i.e. if GetChildren() has
 * 			   been performed on it, delete and create a new child array with the 
 * 			   entries passed. If iChildIdArray is NULL then GetChildren() has not been
 *			   performed on the entry yet, in which case append the passed children.
 */
void CMsvCacheIndexTableEntry::UpdateChildMsvIdsL(RPointerArray<CMsvCacheEntry>& aEntries)
	{
	
	// 1. Return if the block is NULL, i.e. the parent is not in the cache.
	if(NULL == iBlockPtr)
		{
		return;
		}
	
	// 2. Otherwise, find the parent sequentially.
	TMsvId parentId = aEntries[0]->Entry().Parent();
	TInt blockSize = Size();
	for(TInt index = 0 ; index < blockSize ; ++index)
		{
		// 2.1 If the parent is found:
		if((*iBlockPtr)[index]->Entry().Id() == parentId)
			{
			// 2.1.1 If the parent already has a iChildIdArray, i.e. if GetChildren() has
			// been performed on it, delete and create a new child array with the 
			// entries passed. If iChildIdArray is NULL then GetChildren() has not been
			// performed on the entry yet, in which case append the passed children.
			RArray<TMsvId>* childArr = (*iBlockPtr)[index]->ChildIdArray();
			TInt entryCount = aEntries.Count();
			if(NULL == childArr)
				{
				childArr = new(ELeave) RArray<TMsvId>;
				(*iBlockPtr)[index]->SetChildIdArray(childArr);
				}
			else
				{
				childArr->Reset();
				}
			while(0 < entryCount)
				{
				TInt leave = childArr->Append(aEntries[--entryCount]->GetId());
				if(KErrNone != leave)
					{
					childArr->Close();
					delete childArr;
					(*iBlockPtr)[index]->SetChildIdArray(NULL);
					User::Leave(leave);
					}
				}
			return;
			} //if((*iBlockPtr)[index]->Entry().Parent() == parentId)
		} //for(TInt index = 0 ; index < blockSize ; ++index)
	}
	
	
/**
 *SplitBlock
 *This will be called when the block size will be more than 120, this will split the block
 * into 2 blocks.	
 *@param aSplitBlock 	RPointerArray<CMsvCacheEntry>& that will be filled with CMsvCacheEntries,
 *@param aMaxId			The maximum TMsvId of the first block.		 
 *@return void
 *	
 */
void CMsvCacheIndexTableEntry::SplitBlockL(RPointerArray<CMsvCacheEntry>& aSplitBlock)
	{
	TInt size = Size();
	TInt i = size/2;
	while(i < size)
		{
		aSplitBlock.AppendL((*iBlockPtr)[size/2]);
		iBlockPtr->Remove(size/2);
		i++;
		}
	}





#if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)
#ifdef _DEBUG
// To print message index cache.
void CMsvCacheIndexTableEntry::Print(RFileLogger& aLogger)
	{
	_LIT(KId, "       ID: ");
	_LIT(KParentId, "    ParentId: ");
	TInt blockSize = Size();
	for(TInt index=0; index<blockSize; ++index)
		{
		RBuf text;
		text.Create(150);
		text.Append(KId);
		text.AppendNum((*iBlockPtr)[index]->Entry().Id());
		text.Append(KParentId);
		text.AppendNum((*iBlockPtr)[index]->Entry().Parent());
		text.Append(_L("    VisibleEntry: "));
		text.AppendNum((*iBlockPtr)[index]->Entry().VisibleFolderFlag());
		text.Append(_L("	Complete flag:"));
		text.AppendNum((*iBlockPtr)[index]->Entry().Complete());
		text.Append(_L("    	Description:"));
		text.Append((*iBlockPtr)[index]->Entry().iDetails);
		aLogger.Write(text);
		text.Close();
		}
	}
#endif 		// #ifdef _DEBUG
#endif		// #if (defined SYMBIAN_MESSAGESTORE_UNIT_TESTCODE)