userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp
changeset 15 4122176ea935
child 33 0173bcd7697c
equal deleted inserted replaced
0:a41df078684a 15:4122176ea935
       
     1 // Copyright (c) 2008-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 the License "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 // f32\sfat\sl_dir_cache.cpp
       
    15 //
       
    16 //
       
    17 
       
    18 #include "sl_std.h"
       
    19 #include "sl_dir_cache.h"
       
    20 
       
    21 //======================================================================
       
    22 TDynamicDirCachePage::~TDynamicDirCachePage()
       
    23 	{
       
    24 	}
       
    25 
       
    26 /**
       
    27 The static cache page creation function.
       
    28 Cache page objects are not supposed to be created on the stack, so this factory function is required.
       
    29 */
       
    30 TDynamicDirCachePage* TDynamicDirCachePage::NewL(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
       
    31 	{
       
    32 	return new(ELeave) TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr);
       
    33 	}
       
    34 
       
    35 /**
       
    36 Cache page constructor.
       
    37 @param	aOwnerCache	pointer of the cache that owns this page
       
    38 @param	aStartMedPos	the start address on the media that this page caches
       
    39 @param	aStartRamAddr	the start address in the ram that this page content lives
       
    40 */
       
    41 TDynamicDirCachePage::TDynamicDirCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
       
    42 :iStartMedPos(aStartMedPos),
       
    43 iStartRamAddr(aStartRamAddr),
       
    44 iOwnerCache(aOwnerCache),
       
    45 iValid(EFalse),
       
    46 iLocked(EFalse)
       
    47 	{
       
    48 //	__PRINT3(_L("TDynamicDirCachePage::TDynamicDirCachePage(aStartMedPos=%lx, aStartRamAddr=0x%X, aPageSize=%u)"), aStartMedPos, aStartRamAddr, PageSizeInBytes());
       
    49 	iType = EUnknown;
       
    50 	}
       
    51 
       
    52 /////////////////////////////// class CDynamicDirCache::TLookupEntry ///////////////////////////
       
    53 /**
       
    54 Required by RHashSet<TLookupEntry> to identify individual hash set entries.
       
    55 @see	RHashSet
       
    56 */
       
    57 TBool IdentityFunction(const TLookupEntry& aEntry1, const TLookupEntry& aEntry2)
       
    58 	{
       
    59 	// only check starting med pos for hash searching
       
    60 	return aEntry1.iPos == aEntry2.iPos;
       
    61 	}
       
    62 /**
       
    63 Required by RHashSet<TLookupEntry> to generate hash value.
       
    64 @see	RHashSet
       
    65 */
       
    66 TUint32 HashFunction(const TLookupEntry& aEntry)
       
    67 	{
       
    68 	return (DefaultHash::Integer(I64HIGH(aEntry.iPos)) + DefaultHash::Integer(I64LOW(aEntry.iPos)));
       
    69 	}
       
    70 
       
    71 /////////////////////////////// class CDynamicDirCache ///////////////////////////
       
    72 CDynamicDirCache::~CDynamicDirCache()
       
    73 	{
       
    74 //	__PRINT(_L("CDynamicDirCache::~CDynamicDirCache()"));
       
    75 
       
    76 	// we should never decommit locked pages
       
    77     while (!iLockedQ.IsEmpty())
       
    78 		{
       
    79 		TDynamicDirCachePage* page = iLockedQ.Last();
       
    80 		DeQueue(page);		// remove from queue
       
    81 		LookupTblRemove(page->StartPos());	// remove from lookuptable
       
    82 		delete page;
       
    83 		}
       
    84 	ASSERT(iLockedQCount == 0);
       
    85 
       
    86 	while (!iUnlockedQ.IsEmpty())
       
    87 		{
       
    88 		TDynamicDirCachePage* page = iUnlockedQ.Last();
       
    89 		DeQueue(page);		// remove from queue
       
    90 		LookupTblRemove(page->StartPos());	// remove from lookuptable
       
    91 		DecommitPage(page);	// inform cache client to decommit page memory
       
    92 		delete page;
       
    93 		}
       
    94 	ASSERT(iUnlockedQCount == 0);
       
    95 
       
    96 	delete iActivePage;
       
    97 
       
    98 	ASSERT(iLookupTable.Count() == 0);
       
    99 	iLookupTable.Close();
       
   100     if (iCacheMemoryClient)
       
   101     	iCacheMemoryClient->Reset();
       
   102 	}
       
   103 
       
   104 /**
       
   105 Constructor of CDynamicDirCache.
       
   106 @param	aDrive	local drive interface to read/write media
       
   107 @param	aMinPageNum	the minimum page number for the cache, includes iActive page and locked pages.
       
   108 @param	aMaxPageNum	the maximum page number for the cache, includes iActive page, locked pages and unlocked pages.
       
   109 @param	aPageSizeInBytesLog2	the log2 value of page size in bytes, assumes page size is always a power of two
       
   110 */
       
   111 CDynamicDirCache::CDynamicDirCache(TFatDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeInBytesLog2)
       
   112 :iPageSizeLog2(aPageSizeInBytesLog2),
       
   113 iMinSizeInPages(aMinPageNum),
       
   114 iMaxSizeInPages(aMaxPageNum),
       
   115 iDrive(aDrive),
       
   116 iLockedQ(_FOFF(TDynamicDirCachePage, iLink)),
       
   117 iUnlockedQ(_FOFF(TDynamicDirCachePage, iLink)),
       
   118 iLockedQCount(0),
       
   119 iUnlockedQCount(0),
       
   120 iHashFunction(HashFunction),
       
   121 iIdentityFunction(IdentityFunction),
       
   122 iLookupTable(iHashFunction, iIdentityFunction)
       
   123 	{
       
   124 	iPageSizeInBytes = 1 << aPageSizeInBytesLog2;
       
   125 	iCacheDisabled = EFalse;
       
   126     iMinCacheSizeInBytes = aMinPageNum << aPageSizeInBytesLog2;
       
   127     iMaxCacheSizeInBytes = aMaxPageNum << aPageSizeInBytesLog2;
       
   128     ASSERT(iPageSizeInBytes && iPageSizeInBytes <= iMinCacheSizeInBytes && iMinCacheSizeInBytes <= iMaxCacheSizeInBytes);
       
   129 	// initial value, will be reset from outside
       
   130 	iCacheBasePos = 0;
       
   131 	}
       
   132 
       
   133 /**
       
   134 Second phase constructor of CDynamicDirCache.
       
   135 @param	aClientName the identification of cache memeory client this cache connects
       
   136 */
       
   137 void CDynamicDirCache::ConstructL(const TDesC& aClientName)
       
   138 	{
       
   139 //    __PRINT3(_L("CDynamicDirCache::ConstructL(Min=%u, Max=%u, page=%u)"), iMinCacheSizeInBytes, iMaxCacheSizeInBytes, iPageSizeInBytes);
       
   140 	CCacheMemoryManager* manager = CCacheMemoryManagerFactory::CacheMemoryManager();
       
   141 	if (manager)
       
   142 		{
       
   143 		// client will register itself onto cache memory manager when created
       
   144 		// note this operation may leave under OOM condition
       
   145 		iCacheMemoryClient = manager->ConnectClientL(aClientName, iMinSizeInPages * PageSizeInSegs(), iMaxSizeInPages * PageSizeInSegs());
       
   146 		}
       
   147 	else
       
   148 		{
       
   149 		User::Leave(KErrNotSupported);
       
   150 		}
       
   151 
       
   152 	ASSERT(iCacheMemoryClient);
       
   153 	if (!iCacheMemoryClient)
       
   154 		{
       
   155 		User::Leave(KErrNoMemory);
       
   156 		}
       
   157 
       
   158 	// reserve active page
       
   159 	iActivePage = AllocateAndLockNewPageL(0);
       
   160 	ASSERT(iActivePage);
       
   161 	if (!iActivePage)
       
   162 		{
       
   163 		User::Leave(KErrNoMemory);
       
   164 		}
       
   165 	iActivePage->SetPageType(TDynamicDirCachePage::EActivePage);
       
   166 	}
       
   167 
       
   168 /**
       
   169 Static factory function of CDynamicDirCache
       
   170 */
       
   171 CDynamicDirCache* CDynamicDirCache::NewL(TFatDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeLog2, const TDesC& aClientName)
       
   172     {
       
   173 //    __PRINT3(_L("CDynamicDirCache::NewL(MinPageNum=%u, MaxPageNum=%u, page=%u)"), aMinPageNum, aMaxPageNum, 1<<aPageSizeLog2);
       
   174     CDynamicDirCache* pSelf = new (ELeave) CDynamicDirCache(aDrive, aMinPageNum, aMaxPageNum, aPageSizeLog2);
       
   175     CleanupStack::PushL(pSelf);
       
   176     pSelf->ConstructL(aClientName);
       
   177     CleanupStack::Pop();
       
   178     return pSelf;
       
   179     }
       
   180 
       
   181 /**
       
   182 Insert an unlocked page into the last position of the locked queue, may squeeze the original last page into
       
   183 the unlocked queue.
       
   184 This function is used on last visited but 'unlocked' pages to avoid excessive lock/unlock calls to cache memory
       
   185 manager as contiguous entry reading/writing often happens on the same page.
       
   186 @param	aPage	the page to be inserted.
       
   187 @pre	the page type of aPage should only be TDynamicDirCachePage::EUnknown
       
   188 */
       
   189 void CDynamicDirCache::MakePageLastLocked(TDynamicDirCachePage* aPage)
       
   190 	{
       
   191 	// this function should not be called on active pages
       
   192 	ASSERT(aPage->iType == TDynamicDirCachePage::EUnknown);
       
   193 
       
   194 	if (iLockedQ.IsEmpty())
       
   195 		{
       
   196 		// if locked queue is empty, add it onto the locked queue directly
       
   197 		AddFirstOntoQueue(aPage, TDynamicDirCachePage::ELocked);
       
   198 		}
       
   199 	else
       
   200 		{
       
   201 		// otherwise, we squeeze for the last position on locked queue
       
   202 		while (iLockedQCount + 1 >= iMinSizeInPages)
       
   203 			{
       
   204 			TDynamicDirCachePage* last = iLockedQ.Last();
       
   205 			DeQueue(last);
       
   206 			UnlockPage(last);
       
   207 			AddFirstOntoQueue(last, TDynamicDirCachePage::EUnlocked);
       
   208 			}
       
   209 
       
   210 		// iLockedQCount + 1 < iMinSizeInPages
       
   211 		iLockedQ.AddLast(*aPage);
       
   212 		aPage->SetPageType(TDynamicDirCachePage::ELocked);
       
   213 		iLockedQCount++;
       
   214 		}
       
   215 	}
       
   216 
       
   217 /**
       
   218 Read data from a single page. If the page is not found or not valid anymore, read media onto iActive page
       
   219 first.
       
   220 @param	aPos	the starting position of the media address to be read.
       
   221 @param	aLength	the length of the content to be read.
       
   222 @param	aDes	the descriptor to contain the content.
       
   223 @pre	aLength should be no more than page size.
       
   224 */
       
   225 void CDynamicDirCache::ReadDataFromSinglePageL(TInt64 aPos, TInt aLength, TDes8& aDes)
       
   226 	{
       
   227     //-- the data section is in the cache page entirely, take data directly from the cache
       
   228 	TDynamicDirCachePage* pPage = FindPageByPos(aPos);
       
   229     if (pPage)
       
   230     	{
       
   231 		// lock page before reading,
       
   232     	if (LockPage(pPage) != NULL)
       
   233     		{
       
   234     		// read data
       
   235             aDes.Copy(pPage->PtrInPage(aPos), aLength);
       
   236 
       
   237             // if page is from unlocked queue, insert it onto the last page of the locked
       
   238             //  queue. this is to avoid excessive locking and unlocking operations that is
       
   239             //  highly likely to happen for following reads.
       
   240             if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
       
   241             	{
       
   242             	DeQueue(pPage);
       
   243             	MakePageLastLocked(pPage);
       
   244             	}
       
   245     		}
       
   246     	else	// page locking failed
       
   247     		{
       
   248     		ASSERT(pPage->PageType() == TDynamicDirCachePage::EUnlocked);
       
   249     		DeQueue(pPage);
       
   250     		LookupTblRemove(pPage->StartPos());
       
   251     		DecommitPage(pPage);
       
   252     		delete pPage;
       
   253     		pPage = NULL;
       
   254     		}
       
   255     	}
       
   256 
       
   257 	if (!pPage)
       
   258 		{
       
   259         // if page not found or page data not valid anymore, use active page to read data in
       
   260         pPage = UpdateActivePageL(aPos);
       
   261         // read data
       
   262         aDes.Copy(pPage->PtrInPage(aPos), aLength);
       
   263     	}
       
   264 
       
   265 	}
       
   266 
       
   267 //====================================================================
       
   268 /**
       
   269 Implementation of pure virtual function.
       
   270 @see	MWTCacheInterface::ReadL()
       
   271 */
       
   272 void CDynamicDirCache::ReadL(TInt64 aPos, TInt aLength, TDes8& aDes)
       
   273 	{
       
   274 #ifdef _DEBUG
       
   275     if(iCacheDisabled)
       
   276         {
       
   277         // cache is disabled for debug purposes
       
   278         __PRINT(_L("CDynamicDirCache disabled"));
       
   279         User::LeaveIfError(iDrive.ReadNonCritical(aPos, aLength, aDes));
       
   280         return;
       
   281         }
       
   282 #endif //_DEBUG
       
   283 
       
   284     aDes.Zero();
       
   285     const TUint32 PageSz = iPageSizeInBytes;//-- cache page size
       
   286 
       
   287     TInt64 pageStartMedPos = CalcPageStartPos(aPos);
       
   288     const TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos); //-- number of bytes from aPos to the end of the page
       
   289 
       
   290 //    __PRINT5(_L("CDynamicDirCache::ReadL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, aLength, pageStartMedPos, PageSz, bytesToPageEnd);
       
   291     // if all data needed is on a single page
       
   292     if((TUint32)aLength <= bytesToPageEnd)
       
   293         {
       
   294         ReadDataFromSinglePageL(aPos, aLength, aDes);
       
   295         }
       
   296     // or data to be read cross cache page boundary or probably we have more than 1 page to read
       
   297     else
       
   298         {
       
   299         __PRINT(_L("CDynamicDirCache::ReadL() CROSS PAGE!"));
       
   300         TUint32 dataLen(aLength);   //-- current data length
       
   301         TInt64  currMediaPos(aPos); //-- current media position
       
   302 
       
   303         //-- 1. read data that are already in the current page
       
   304         ReadDataFromSinglePageL(currMediaPos, bytesToPageEnd, aDes);
       
   305         dataLen -= bytesToPageEnd;
       
   306         currMediaPos += bytesToPageEnd;
       
   307 
       
   308         TPtr8 dataNext = aDes.MidTPtr(aDes.Length());
       
   309 
       
   310         //-- 2. read whole pages of data
       
   311         while (dataLen >= PageSz)
       
   312         	{
       
   313         	//-- find out if currMediaPos is in cache. If not, find a spare page and read data there
       
   314         	ReadDataFromSinglePageL(currMediaPos, PageSz, dataNext);
       
   315             currMediaPos += PageSz;
       
   316             dataLen -= PageSz;
       
   317             dataNext = dataNext.MidTPtr(dataNext.Length());
       
   318         	}
       
   319 
       
   320         //-- 3. read the rest of the data
       
   321         if(dataLen > 0)
       
   322             {
       
   323         	ReadDataFromSinglePageL(currMediaPos, dataLen, dataNext);
       
   324             }
       
   325         } //else((TUint32)aLength <= bytesToPageEnd)
       
   326 	}
       
   327 
       
   328 /**
       
   329 Write data through a single page. If the page is not found or not valid anymore, read media onto iActive page
       
   330 first, then write data through iActive page.
       
   331 @param	aPos	the starting position of the media address to be write.
       
   332 @param	aData	the starting address that the writing content lives in the ram.
       
   333 @param	aDataLen	the length of the content to be written.
       
   334 @pre	aDataLen	should be no more than page size.
       
   335 */
       
   336 void CDynamicDirCache::WriteDataOntoSinglePageL(TInt64 aPos, const TUint8* aData, TUint32 aDataLen)
       
   337 	{
       
   338 	ASSERT(aDataLen <= iPageSizeInBytes);
       
   339     //-- the data section is in the cache page entirely, take data directly from the cache
       
   340 	TDynamicDirCachePage* pPage = FindPageByPos(aPos);
       
   341     if (pPage)
       
   342     	{
       
   343 		// lock page before writing,
       
   344     	if (LockPage(pPage) != NULL)
       
   345     		{
       
   346     		//-- update cache
       
   347             Mem::Copy(pPage->PtrInPage(aPos), aData, aDataLen);
       
   348     		}
       
   349     	else
       
   350     		{
       
   351     		ASSERT(pPage->PageType() == TDynamicDirCachePage::EUnlocked);
       
   352     		DeQueue(pPage);
       
   353     		LookupTblRemove(pPage->StartPos());
       
   354     		DecommitPage(pPage);
       
   355     		delete pPage;
       
   356     		pPage = NULL;
       
   357     		}
       
   358     	}
       
   359 
       
   360     // if page not found or page data not valid anymore, use active page to read data in
       
   361     if (!pPage)
       
   362     	{
       
   363         pPage = UpdateActivePageL(aPos);
       
   364         //-- update cache
       
   365         Mem::Copy(pPage->PtrInPage(aPos), aData, aDataLen);
       
   366     	}
       
   367 
       
   368 	// make sure the page is unlocked after use
       
   369 	if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
       
   370 		{
       
   371 		UnlockPage(pPage);
       
   372 		}
       
   373 
       
   374 	// always make writting events MRU
       
   375 	MakePageMRU(aPos);
       
   376     return;
       
   377 	}
       
   378 
       
   379 /**
       
   380 Implementation of pure virtual function.
       
   381 @see	MWTCacheInterface::WriteL()
       
   382 */
       
   383 void CDynamicDirCache::WriteL(TInt64 aPos,const TDesC8& aDes)
       
   384 	{
       
   385 #ifdef _DEBUG
       
   386     if(iCacheDisabled)
       
   387         {
       
   388         // cache is disabled for debug purposes
       
   389         __PRINT(_L("CDynamicDirCache disabled"));
       
   390         User::LeaveIfError(iDrive.WriteCritical(aPos,aDes));
       
   391         return;
       
   392         }
       
   393 #endif //_DEBUG
       
   394 
       
   395     TUint32 dataLen = aDes.Size();
       
   396     const TUint8* pData   = aDes.Ptr();
       
   397     const TUint32 PageSz  = iPageSizeInBytes; //-- cache page size
       
   398 
       
   399     TInt64 pageStartMedPos = CalcPageStartPos(aPos);
       
   400     TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos);
       
   401 
       
   402 //    __PRINT5(_L("CDynamicDirCache::WriteL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, dataLen, pageStartMedPos, PageSz, bytesToPageEnd);
       
   403 
       
   404     if(dataLen <= bytesToPageEnd)
       
   405         {
       
   406         WriteDataOntoSinglePageL(aPos, pData, dataLen);
       
   407         }
       
   408     else
       
   409         {
       
   410         __PRINT(_L("CDynamicDirCache::WriteL() CROSS PAGE!"));
       
   411 
       
   412         //-- Data to be written cross cache page boundary or probably we have more than 1 page to write
       
   413         TInt64  currMediaPos(aPos);
       
   414 
       
   415         //-- 1. update the current page
       
   416         WriteDataOntoSinglePageL(currMediaPos, pData, bytesToPageEnd);
       
   417 
       
   418         pData += bytesToPageEnd;
       
   419         currMediaPos += bytesToPageEnd;
       
   420         dataLen -= bytesToPageEnd;
       
   421 
       
   422         //-- 2. write whole pages of data to the cache
       
   423         while (dataLen >= PageSz)
       
   424         	{
       
   425             WriteDataOntoSinglePageL(currMediaPos, pData, PageSz);
       
   426 
       
   427             pData += PageSz;
       
   428             currMediaPos += PageSz;
       
   429             dataLen -= PageSz;
       
   430         	}
       
   431 
       
   432         //-- 3. write the rest of the data
       
   433         if(dataLen > 0)
       
   434             {
       
   435             WriteDataOntoSinglePageL(currMediaPos, pData, dataLen);
       
   436             }
       
   437         }// else(dataLen <= bytesToPageEnd)
       
   438 
       
   439 
       
   440     //-- write data to the media
       
   441     const TInt nErr = iDrive.WriteCritical(aPos,aDes);
       
   442     if(nErr != KErrNone)
       
   443         {//-- some serious problem occured during writing, invalidate cache.
       
   444         InvalidateCache();
       
   445         User::Leave(nErr);
       
   446         }
       
   447 	}
       
   448 
       
   449 /**
       
   450 Implementation of pure virtual function.
       
   451 @see	MWTCacheInterface::InvalidateCache()
       
   452 */
       
   453 void CDynamicDirCache::InvalidateCache(void)
       
   454 	{
       
   455 	__PRINT2(_L("CDynamicDirCache::InvalidateCache(locked=%d, unlocked=%d)"), iLockedQCount, iUnlockedQCount);
       
   456 	// we should never decommit locked pages as they needs to be reserved anyway
       
   457 	// the overhead of unnecessary page committing operations
       
   458 	while(!iLockedQ.IsEmpty())
       
   459 		{
       
   460 		TDynamicDirCachePage* page = iLockedQ.Last();
       
   461 		DeQueue(page);						// remove from queue
       
   462 		LookupTblRemove(page->StartPos());	// remove from lookuptable
       
   463 		delete page;
       
   464 		}
       
   465 	ASSERT(iLockedQCount == 0);
       
   466 
       
   467 	// however we should decommit unlocked pages here
       
   468 	while (!iUnlockedQ.IsEmpty())
       
   469 		{
       
   470 		TDynamicDirCachePage* page = iUnlockedQ.Last();
       
   471 		DeQueue(page);						// remove from queue
       
   472 		LookupTblRemove(page->StartPos());	// remove from lookuptable
       
   473 		DecommitPage(page);					// inform cache client to decommit page memory
       
   474 		delete page;
       
   475 		}
       
   476 	ASSERT(iUnlockedQCount == 0);
       
   477 
       
   478     ASSERT(iLookupTable.Count() == 0);
       
   479 	iLookupTable.Close();
       
   480 
       
   481 	ASSERT(iCacheMemoryClient);
       
   482 
       
   483 	// initialize cache state.
       
   484 	// Note that once the client is reset, all pages lose connection with the client
       
   485 	//	including the active page. So we will need to reset and re-allocate active page
       
   486 	//	properly.
       
   487 	if (iCacheMemoryClient)
       
   488     	iCacheMemoryClient->Reset();
       
   489 
       
   490 	// reset and re-allocate active page
       
   491 	ResetPagePos(iActivePage);				// reset start media position (0), invalidate page content
       
   492 	TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs());
       
   493 	// this should always succeed as the client has just been reset and there are always reserved pages
       
   494 	ASSERT(startRamAddr);
       
   495 	iActivePage->SetStartPtr(startRamAddr);	// set RAM address
       
   496 	}
       
   497 
       
   498 
       
   499 /** this method isn't implemented*/
       
   500 void CDynamicDirCache::InvalidateCachePage(TUint64 /*aPos*/)
       
   501     {
       
   502     ASSERT(0);
       
   503     }
       
   504 
       
   505 
       
   506 /**
       
   507 Implementation of pure virtual function.
       
   508 @see	MWTCacheInterface::PosCached()
       
   509 */
       
   510 TUint32 CDynamicDirCache::PosCached(const TInt64& aPos, TInt64& aCachedPosStart)
       
   511 	{
       
   512 	const TInt64 pageStartMedPos = CalcPageStartPos(aPos);
       
   513 
       
   514 	// only search the page in lookup table
       
   515 	// NOTE: we don't count the active page into acount here,
       
   516 	// this is to avoid pulling next pages recursively
       
   517 	TDynamicDirCachePage* pPage = LookupTblFind(pageStartMedPos);
       
   518 
       
   519 	// then check if page is still valid if page is on Unlocked Page Queue
       
   520 	if (pPage && pPage->PageType() == TDynamicDirCachePage::EUnlocked)
       
   521 		{
       
   522 		if (LockPage(pPage) != NULL)
       
   523 			{
       
   524 //			__PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) found on Unlocked Queue!"), aPos);
       
   525 			// have to unlock it before returning, otherwise there will be memory leak
       
   526 			UnlockPage(pPage);
       
   527     	    aCachedPosStart = pPage->StartPos();
       
   528 			return pPage->PageSizeInBytes();
       
   529 			}
       
   530 		else	// if the unlocked page is not valid anymore, remove it
       
   531 			{
       
   532     		DeQueue(pPage);
       
   533     		LookupTblRemove(pPage->StartPos());
       
   534     		DecommitPage(pPage);
       
   535     		delete pPage;
       
   536     		pPage = NULL;
       
   537 			}
       
   538 		}
       
   539 	// otherwise if page is already locked or valid active page
       
   540 	else if (pPage)
       
   541 		{
       
   542 		__PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) on Locked Queue!"), aPos);
       
   543 	    aCachedPosStart = pPage->StartPos();
       
   544 		return pPage->PageSizeInBytes();
       
   545 		}
       
   546 
       
   547 	// page is not found or not valid anymore
       
   548 	return 0;
       
   549 	}
       
   550 
       
   551 /**
       
   552 Implementation of pure virtual function.
       
   553 @see	MWTCacheInterface::CacheSizeInBytes()
       
   554 */
       
   555 TUint32 CDynamicDirCache::CacheSizeInBytes()  const
       
   556 	{
       
   557 	return iMaxCacheSizeInBytes;
       
   558 	}
       
   559 
       
   560 /**
       
   561 Implementation of pure virtual function.
       
   562 @see	MWTCacheInterface::Control()
       
   563 */
       
   564 TInt CDynamicDirCache::Control(TUint32 aFunction, TUint32 aParam1, TAny* aParam2)
       
   565 	{
       
   566     TInt r = KErrNotSupported;
       
   567 #ifdef _DEBUG
       
   568     (void)aParam2;
       
   569     switch(aFunction)
       
   570         {
       
   571         // disable / enable cache, for debug
       
   572         // if aParam1 != 0 cache will be disabled, enabled otherwise
       
   573         case EDisableCache:
       
   574             iCacheDisabled = aParam1 ? 1 : 0;
       
   575             r = KErrNone;
       
   576         break;
       
   577 
       
   578         // dump cache, for debug
       
   579         case EDumpCache:
       
   580         	{
       
   581         	RFs fs;
       
   582         	fs.Connect();
       
   583         	const TUint32 debugRegister = DebugRegister();
       
   584         	fs.SetDebugRegister(debugRegister|KFSYS);
       
   585         	Dump();
       
   586         	fs.SetDebugRegister(debugRegister);
       
   587         	fs.Close();
       
   588         	break;
       
   589         	}
       
   590         case ECacheInfo:
       
   591         	{
       
   592         	RFs fs;
       
   593         	fs.Connect();
       
   594         	const TUint32 debugRegister = DebugRegister();
       
   595         	fs.SetDebugRegister(debugRegister|KFSYS);
       
   596         	Info();
       
   597         	fs.SetDebugRegister(debugRegister);
       
   598         	fs.Close();
       
   599         	break;
       
   600         	}
       
   601 
       
   602         default:
       
   603             __PRINT1(_L("CDynamicDirCache::Control() invalid function: %d"), aFunction);
       
   604             ASSERT(0);
       
   605         break;
       
   606         }
       
   607 
       
   608 #else
       
   609     (void)aFunction; //-- supress warnings
       
   610     (void)aParam1;
       
   611     (void)aParam2;
       
   612     User::Invariant(); //-- don't call this method in release build
       
   613 #endif //_DEBUG
       
   614 
       
   615     return r;
       
   616 	}
       
   617 
       
   618 /**
       
   619 Implementation of pure virtual function.
       
   620 @see	MWTCacheInterface::SetCacheBasePos()
       
   621 */
       
   622 void CDynamicDirCache::SetCacheBasePos(TInt64 aBasePos)
       
   623 	{
       
   624 	iCacheBasePos = aBasePos;
       
   625 	}
       
   626 
       
   627 /**
       
   628 Implementation of pure virtual function.
       
   629 @see	MWTCacheInterface::SetCacheBasePos()
       
   630 */
       
   631 TUint32 CDynamicDirCache::PageSizeInBytesLog2() const
       
   632 	{
       
   633 	return iPageSizeLog2;
       
   634 	}
       
   635 
       
   636 /**
       
   637 Implementation of pure virtual function.
       
   638 @see	MWTCacheInterface::MakePageMRU()
       
   639 */
       
   640 void CDynamicDirCache::MakePageMRU(TInt64 aPos)
       
   641 	{
       
   642 	__PRINT1(_L("MakePageMRU (%lx)"), aPos);
       
   643 //	__PRINT4(_L("Current Cache State: iLockedQCount=%d, iUnlockedQCount=%d, iLookupTbl=%d, iMaxSizeInPages=%d"), iLockedQCount, iUnlockedQCount, iLookupTable.Count(), iMaxSizeInPages);
       
   644 	// check the MRU page first, if it is already the MRU page, we can return immediately
       
   645 	TInt64 pageStartMedPos = CalcPageStartPos(aPos);
       
   646 	if (!iLockedQ.IsEmpty())
       
   647 		{
       
   648 		if (iLockedQ.First()->StartPos() == pageStartMedPos)
       
   649 			{
       
   650 			return;
       
   651 			}
       
   652 		}
       
   653 
       
   654 	TDynamicDirCachePage* pPage = FindPageByPos(aPos);
       
   655     if (pPage)
       
   656     	{
       
   657     	ASSERT(pPage->IsValid());
       
   658 		// lock page before make it MRU
       
   659     	if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
       
   660     		{
       
   661     		ASSERT(!pPage->IsLocked());
       
   662         	if (LockPage(pPage) == NULL)
       
   663         		{
       
   664         		DeQueue(pPage);
       
   665         		LookupTblRemove(pPage->StartPos());
       
   666         		DecommitPage(pPage);
       
   667         		delete pPage;
       
   668         		pPage = NULL;
       
   669         		}
       
   670     		}
       
   671     	else
       
   672     		{
       
   673     		// error checking: page should either be locked or active
       
   674     		ASSERT(LockPage(pPage) != NULL);
       
   675     		}
       
   676     	}
       
   677 
       
   678     // if page not found or page data not valid anymore, use active page to read data
       
   679     if (!pPage)
       
   680     	{
       
   681         TRAPD(err, pPage = UpdateActivePageL(aPos));
       
   682         if (err != KErrNone)
       
   683         	{
       
   684         	// problem occurred reading active page, return immediately.
       
   685         	return;
       
   686         	}
       
   687     	}
       
   688 
       
   689     // by now, the page is either locked or active page
       
   690 	ASSERT(pPage && pPage->IsValid() && pPage->IsLocked());
       
   691 
       
   692 	switch (pPage->PageType())
       
   693 		{
       
   694 		// if the page is the active page, we will need to find a new active page for replacement
       
   695 		case TDynamicDirCachePage::EActivePage:
       
   696 			{
       
   697 			TDynamicDirCachePage* newAP = NULL;
       
   698 			// if there is more cache room available, try to create a new page first
       
   699 			if (!CacheIsFull())
       
   700 				{
       
   701 				// allocate and lock a new page
       
   702 				TRAPD(err, newAP = AllocateAndLockNewPageL(0));
       
   703 				// if any error ocurrs, return immediately
       
   704 				if (err != KErrNone)
       
   705 					{
       
   706 					// unlock the page that was originally unlocked before leave
       
   707 					if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
       
   708 						{
       
   709 						UnlockPage(pPage);
       
   710 						}
       
   711 					return;
       
   712 					}
       
   713 
       
   714 				if (newAP)
       
   715 					{
       
   716 					// replace the active page with the new page
       
   717 					newAP->SetPageType(TDynamicDirCachePage::EActivePage);
       
   718 					iActivePage = newAP;
       
   719 					}
       
   720 				}
       
   721 
       
   722 			// if cache has grown to its max size, or new page allocation failed
       
   723 			if (!newAP)
       
   724 				{
       
   725 				// try to lock the LRU page on the unlocked page queque first
       
   726 				if (!iUnlockedQ.IsEmpty())
       
   727 					{
       
   728 					newAP = iUnlockedQ.Last();
       
   729 					ASSERT(newAP->IsValid());
       
   730 					if (LockPage(newAP) != NULL)
       
   731 						{
       
   732 						// deque, reset pos, set new type
       
   733 						DeQueue(newAP);
       
   734 		        		LookupTblRemove(newAP->StartPos());
       
   735 						ResetPagePos(newAP);
       
   736 						newAP->SetPageType(TDynamicDirCachePage::EActivePage);
       
   737 						// replace active page
       
   738 						iActivePage = newAP;
       
   739 						}
       
   740 					// if falied locking the LRU page from unclocked queque,
       
   741 					// delete it
       
   742 					else
       
   743 						{
       
   744 						DeQueue(newAP);
       
   745 		        		LookupTblRemove(newAP->StartPos());
       
   746 		        		DecommitPage(newAP);
       
   747 		        		delete newAP;
       
   748 		        		newAP = NULL;
       
   749 						}
       
   750 					}
       
   751 				}
       
   752 
       
   753 			// if still have not found new active page
       
   754 			// grab the LRU page from Locked Page Queue for active page
       
   755 			if (!newAP)
       
   756 				{
       
   757 				ASSERT(!iLockedQ.IsEmpty());
       
   758 				newAP = iLockedQ.Last();
       
   759 				// deque, reset pos, set new type
       
   760 				DeQueue(newAP);
       
   761         		LookupTblRemove(newAP->StartPos());
       
   762 				ResetPagePos(newAP);
       
   763 				newAP->SetPageType(TDynamicDirCachePage::EActivePage);
       
   764 				// replace active page
       
   765 				iActivePage = newAP;
       
   766 				}
       
   767 
       
   768 			// we should always be able to find a locked page for active page
       
   769 			ASSERT(newAP != NULL);
       
   770 
       
   771 			// make original page (i.e. former active page) MRU
       
   772 			// add onto locked queue
       
   773 			AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
       
   774 			// add onto lookuptbl, as active page is not on lookup tbl originally
       
   775 			LookupTblAdd(pPage);
       
   776 			// check cache limit
       
   777 			CheckThresholds();
       
   778 			return;
       
   779 			}
       
   780 		case TDynamicDirCachePage::EUnlocked:
       
   781 			{
       
   782 			// if page was originally on Unlocked Page Queque, remove it from Unlocked Page Queue, add it
       
   783 			// to the Locked Page Queue and make it MRU
       
   784 			DeQueue(pPage);
       
   785 			AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
       
   786 			// check cache limit
       
   787 			CheckThresholds();
       
   788 			return;
       
   789 			}
       
   790 		case TDynamicDirCachePage::ELocked:
       
   791 			{
       
   792 			// otherwise the page was on Locked Page Queue, make it MRU
       
   793 			// no need to check cache limit
       
   794 			if (pPage != iLockedQ.First())
       
   795 				{
       
   796 				DeQueue(pPage);
       
   797 				AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
       
   798 				return;
       
   799 				}
       
   800 			break;
       
   801 			}
       
   802 		default:
       
   803 			ASSERT(0);
       
   804 		}
       
   805 	}
       
   806 
       
   807 //====================================================================
       
   808 /**
       
   809 Internal query function, to check if aPos is cached or not. iActive page is included in searching.
       
   810 */
       
   811 TDynamicDirCachePage* CDynamicDirCache::FindPageByPos(TInt64 aPos)
       
   812 	{
       
   813 	__PRINT1(_L("CDynamicDirCache::FindPageByPos(aPos=%lx)"), aPos);
       
   814     // align the page position
       
   815 	TInt64 pageStartMedPos = CalcPageStartPos(aPos);
       
   816 
       
   817 	if ((iActivePage->StartPos() == pageStartMedPos))
       
   818 		{
       
   819 		ASSERT(iActivePage->IsValid());
       
   820 		return iActivePage;
       
   821 		}
       
   822 
       
   823 	// search in lookup table
       
   824 	return LookupTblFind(pageStartMedPos);
       
   825 	}
       
   826 
       
   827 /**
       
   828 read a page length data into iActive page and return iActive page if read is successful.
       
   829 */
       
   830 TDynamicDirCachePage* CDynamicDirCache::UpdateActivePageL(TInt64 aPos)
       
   831 	{
       
   832     // align the page position
       
   833 	TInt64 pageStartMedPos = CalcPageStartPos(aPos);
       
   834 
       
   835 	if (iActivePage->StartPos() == pageStartMedPos && iActivePage->IsValid())
       
   836 		{
       
   837 		return iActivePage;
       
   838 		}
       
   839 
       
   840 	__PRINT2(_L("CDynamicDirCache::UpdateActivePageL(aPos=%lx, active=%lx)"), aPos, iActivePage->StartPos());
       
   841 
       
   842 	// set start med pos value, no other effects, only available to active page
       
   843 	iActivePage->SetPos(pageStartMedPos);
       
   844 
       
   845 	// read data, make active page valid
       
   846 	TUint8* data = iActivePage->PtrInPage(iActivePage->iStartMedPos);
       
   847     TPtr8 dataPtr(data, iPageSizeInBytes);
       
   848     const TInt nErr = iDrive.ReadNonCritical(iActivePage->iStartMedPos, iPageSizeInBytes, dataPtr);
       
   849     if(nErr !=KErrNone)
       
   850         {
       
   851         // some serious problem occured during reading, invalidate cache.
       
   852         InvalidateCache();
       
   853         User::Leave(nErr);
       
   854         }
       
   855     iActivePage->SetValid(ETrue);
       
   856 
       
   857     return iActivePage;
       
   858 	}
       
   859 
       
   860 /**
       
   861 Check if the number of (locked pages + iActive page) and unlocked pages have exceeded minimum allowed page
       
   862 number and maximum allowed page number respectively.
       
   863 */
       
   864 void CDynamicDirCache::CheckThresholds()
       
   865 	{
       
   866 	while (iLockedQCount + 1 > iMinSizeInPages)
       
   867 		{
       
   868 		TDynamicDirCachePage* movePage = iLockedQ.Last();
       
   869 		UnlockPage(movePage);
       
   870 		DeQueue(movePage);
       
   871 		TInt err = LookupTblRemove(movePage->StartPos());
       
   872 		ASSERT(err == KErrNone);
       
   873 
       
   874 		// if it is a valid page, add onto unlocked queue
       
   875 		if (movePage->StartPos() != 0)
       
   876 			{
       
   877 			ASSERT(movePage->IsValid());
       
   878 			AddFirstOntoQueue(movePage, TDynamicDirCachePage::EUnlocked);
       
   879 			err = LookupTblAdd(movePage);
       
   880 			ASSERT(err == KErrNone);
       
   881 			}
       
   882 		else // reserved page, delete
       
   883 			{
       
   884 			DecommitPage(movePage);
       
   885 			delete movePage;
       
   886 			}
       
   887 		}
       
   888 
       
   889 	// if unlocked queue exceeds limit, delete LRU page
       
   890 	// note: all pages on unlocked queue should be valid
       
   891 	while (iUnlockedQCount > iMaxSizeInPages - iMinSizeInPages)
       
   892 		{
       
   893 		TDynamicDirCachePage* removePage = iUnlockedQ.Last();
       
   894 		ASSERT(removePage->StartPos() != 0 && removePage->IsValid());
       
   895 		DeQueue(removePage);
       
   896 		LookupTblRemove(removePage->StartPos());
       
   897 		DecommitPage(removePage);
       
   898 		delete removePage;
       
   899 		}
       
   900 	}
       
   901 
       
   902 /**
       
   903 Try to create a new page and lock the page content when it is created. This function should only be called
       
   904 when creating iActive page or making a page MRU (which might result in page evictions).
       
   905 @return	the pointer of the newly created page, or NULL if allocation failed.
       
   906 @param	aStartMedPos	the starting media address of the page to be created.
       
   907 @pre	aStartMedPos should not already be existing in the cache.
       
   908 */
       
   909 TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPageL(TInt64 aStartMedPos)
       
   910 	{
       
   911 	__PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPageL(aStartMedPos=%lx)"), aStartMedPos);
       
   912 
       
   913 	TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs());
       
   914 	if (startRamAddr)
       
   915 		{
       
   916 		// create new page and return
       
   917 		TDynamicDirCachePage* pPage = TDynamicDirCachePage::NewL(this, aStartMedPos, startRamAddr);
       
   918 		pPage->SetLocked(ETrue);
       
   919 		pPage->SetValid(EFalse);
       
   920 		return pPage;
       
   921 		}
       
   922 
       
   923 	return NULL;
       
   924 	}
       
   925 
       
   926 #ifdef _DEBUG
       
   927 /**
       
   928 Dump cache information, only enabled in debug mode.
       
   929 @see CDynamicDirCache::Control()
       
   930 */
       
   931 void CDynamicDirCache::Info() const
       
   932 	{
       
   933 	__PRINT(_L("======== CDynamicDirCache::Info ========="));
       
   934 	const TUint32 SegmentSizeInBytesLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2();
       
   935 	// page size
       
   936 	__PRINT1(_L("=== Pages size:               [%d Bytes]"), iPageSizeInBytes);
       
   937 	__PRINT1(_L("=== Segment size:             [%d Bytes]"), 1 << SegmentSizeInBytesLog2);
       
   938 
       
   939 	// data size:
       
   940 	__PRINT1(_L("=== Min data size:            [%d Bytes]"), iMinSizeInPages << iPageSizeLog2);
       
   941 	__PRINT1(_L("=== Max data size:            [%d Bytes]"), iMaxSizeInPages << iPageSizeLog2);
       
   942 
       
   943 	// memory size:
       
   944 	const TUint32 pageMemSizeLog2 = iPageSizeLog2 > SegmentSizeInBytesLog2 ? iPageSizeLog2 : SegmentSizeInBytesLog2;
       
   945 	__PRINT1(_L("=== Min memory size:          [%d Bytes]"), iMinSizeInPages << pageMemSizeLog2);
       
   946 	__PRINT1(_L("=== Max memory size:          [%d Bytes]"), iMaxSizeInPages << pageMemSizeLog2);
       
   947 
       
   948 	// reserved pages
       
   949 	__PRINT1(_L("=== Number of pages reserved: [%d]"), iMinSizeInPages);
       
   950 	__PRINT1(_L("=== Reserved memory:          [%d Bytes]"), (iMinSizeInPages * PageSizeInSegs()) << SegmentSizeInBytesLog2);
       
   951 	// locked page num
       
   952 	__PRINT1(_L("=== Number of pages locked:   [%d]"), iLockedQCount);
       
   953 	__PRINT1(_L("=== Locked memory:            [%d Bytes]"), (iLockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2);
       
   954 	// unlocked page num
       
   955 	__PRINT1(_L("=== Number of pages unlocked: [%d]"), iUnlockedQCount);
       
   956 	__PRINT1(_L("=== Unlocked memory:          [%d Bytes]"), (iUnlockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2);
       
   957 	}
       
   958 
       
   959 /**
       
   960 Dump cache content, only enabled in debug mode.
       
   961 @see CDynamicDirCache::Control()
       
   962 */
       
   963 void CDynamicDirCache::Dump()
       
   964 	{
       
   965 	__PRINT(_L("======== CDynamicDirCache::Dump ========="));
       
   966 	if (!iLockedQ.IsEmpty())
       
   967 		{
       
   968 		TDblQueIter<TDynamicDirCachePage> q(iLockedQ);
       
   969 		q.SetToFirst();
       
   970 		TInt i = 0;
       
   971 		while((TDynamicDirCachePage*)q)
       
   972 			{
       
   973 			TDynamicDirCachePage* pP = q++;
       
   974 			__PRINT3(_L("=== CDynamicDirCache::iLockedQ\t[%4d](pos=%lx, size=%d)"), i++, pP->StartPos(), pP->PageSizeInBytes());
       
   975 			}
       
   976 		}
       
   977 	if (!iUnlockedQ.IsEmpty())
       
   978 		{
       
   979 		TDblQueIter<TDynamicDirCachePage> q(iUnlockedQ);
       
   980 		q.SetToFirst();
       
   981 		TInt i = 0;
       
   982 		while((TDynamicDirCachePage*)q)
       
   983 			{
       
   984 			TDynamicDirCachePage* pP = q++;
       
   985 			__PRINT3(_L("=== CDynamicDirCache::iUnlockedQ\t[%4d](pos=%lx, size=%u)"), i++, pP->StartPos(), pP->PageSizeInBytes());
       
   986 			}
       
   987 		}
       
   988 	__PRINT2(_L("=== CDynamicDirCache::iActivePage\t[*](pos=%lx, size=%u)"), iActivePage->StartPos(), iActivePage->PageSizeInBytes());
       
   989 
       
   990 	if (iLookupTable.Count())
       
   991 		{
       
   992 		TInt i = 0;
       
   993 		THashSetIter<TLookupEntry> iter(iLookupTable);
       
   994 		TLookupEntry* pEntry;
       
   995 		pEntry = (TLookupEntry*) iter.Next();
       
   996 		while(pEntry)
       
   997 			{
       
   998 			TDynamicDirCachePage* pP = pEntry->iPage;
       
   999 			__PRINT3(_L("=== CDynamicDirCache::iLookupTable\t[%4d](pos=%lx, size=%u)"), i++, pP->StartPos(), pP->PageSizeInBytes());
       
  1000 			pEntry = (TLookupEntry*) iter.Next();
       
  1001 			};
       
  1002 		}
       
  1003 	__PRINT(_L("===========================================\n"));
       
  1004 	}
       
  1005 #endif //_DEBUG
       
  1006 
       
  1007 /**
       
  1008 Lock an unlocked page, or do nothing if the page is already locked.
       
  1009 @return	TUint8*	pointer of the page to be locked, if locking is successful, otherwise return NULL.
       
  1010 @param	aPage	the pointer of the page to be locked.
       
  1011 */
       
  1012 TUint8* CDynamicDirCache::LockPage(TDynamicDirCachePage* aPage)
       
  1013 	{
       
  1014 	ASSERT(aPage != NULL);
       
  1015 	if (aPage->IsLocked())
       
  1016 		return aPage->StartPtr();
       
  1017 
       
  1018 	TInt r = iCacheMemoryClient->LockSegments(aPage->StartPtr(), PageSizeInSegs());
       
  1019 	if (r == KErrNone)
       
  1020 		{
       
  1021 		aPage->SetLocked(ETrue);
       
  1022 		return aPage->StartPtr();
       
  1023 		}
       
  1024 
       
  1025 	return NULL;
       
  1026 	}
       
  1027 
       
  1028 /**
       
  1029 Unlock a locked page.
       
  1030 @return	TInt	KErrNone if unlocking was successful, otherwise system-wide error code.
       
  1031 @param	aPage	the pointer of the page to be unlocked.
       
  1032 */
       
  1033 TInt CDynamicDirCache::UnlockPage(TDynamicDirCachePage* aPage)
       
  1034 	{
       
  1035 	ASSERT(aPage != NULL);
       
  1036 	__PRINT1(_L("CDynamicDirCache::UnlockPage(%lx)"), aPage->StartPos());
       
  1037 	TInt r = iCacheMemoryClient->UnlockSegments(aPage->StartPtr(), PageSizeInSegs());
       
  1038 	if (r == KErrNone)
       
  1039 		{
       
  1040 		aPage->SetLocked(EFalse);
       
  1041 		}
       
  1042 	return r;
       
  1043 	}
       
  1044 
       
  1045 /**
       
  1046 Decommit a locked or unlocked page.
       
  1047 @return	TInt	KErrNone if decommition was successful, otherwise system-wide error code.
       
  1048 @param	aPage	the pointer of the page to be decommitted.
       
  1049 */
       
  1050 TInt CDynamicDirCache::DecommitPage(TDynamicDirCachePage* aPage)
       
  1051 	{
       
  1052 	ASSERT(aPage != NULL);
       
  1053 	__PRINT1(_L("CDynamicDirCache::DecommitPage(%lx)"), aPage->StartPos());
       
  1054 	if (aPage)
       
  1055 		{
       
  1056 		TInt r = iCacheMemoryClient->DecommitSegments(aPage->StartPtr(), PageSizeInSegs());
       
  1057 		if (r == KErrNone)
       
  1058 			{
       
  1059 			aPage->SetLocked(EFalse);
       
  1060 			aPage->SetValid(EFalse);
       
  1061 			}
       
  1062 		return r;
       
  1063 		}
       
  1064 	return KErrArgument;
       
  1065 	}
       
  1066 
       
  1067 /////////////////////////// aluxiliary functions //////////////////////////////////
       
  1068 /**
       
  1069 Calculate the page size in segments. Segment size is the size of the kernel memory unit that cache memory manager manages.
       
  1070 We are making assumption here about the page size: page size should always be either less than segment size
       
  1071 or multiple times of segment size
       
  1072 @return	TUint32	the page size in segments.
       
  1073 */
       
  1074 TUint32 CDynamicDirCache::PageSizeInSegs() const
       
  1075 	{
       
  1076 	// initialize cache memory manager as all file systems have mounted by now
       
  1077 	ASSERT(CCacheMemoryManagerFactory::CacheMemoryManager());
       
  1078 	const TUint32 SegmentSizeInBytesLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2();
       
  1079 
       
  1080 	// Page size should be non-zero
       
  1081 	ASSERT(iPageSizeInBytes);
       
  1082 
       
  1083 	TUint32 segs = iPageSizeInBytes >> SegmentSizeInBytesLog2;
       
  1084 	return segs > 0 ? segs : 1;
       
  1085 	}
       
  1086 
       
  1087 /**
       
  1088 Deque the page from locked queue or unlocked queue. All pages are managed through these two queues, expect iActive
       
  1089 page.
       
  1090 @param	aPage	the pointer of the page to be dequeued
       
  1091 @return	TInt	KErrArgument if aPage is invalid, otherwise KErrNone.
       
  1092 */
       
  1093 TInt CDynamicDirCache::DeQueue(TDynamicDirCachePage* aPage)
       
  1094 	{
       
  1095 	ASSERT(aPage);
       
  1096 	if (!aPage)
       
  1097 		return KErrArgument;
       
  1098 
       
  1099 	if (aPage->iType == TDynamicDirCachePage::ELocked)
       
  1100 		{
       
  1101 		aPage->Deque();
       
  1102 		aPage->SetPageType(TDynamicDirCachePage::EUnknown);
       
  1103 		--iLockedQCount;
       
  1104 		}
       
  1105 	else if (aPage->iType == TDynamicDirCachePage::EUnlocked)
       
  1106 		{
       
  1107 		aPage->Deque();
       
  1108 		aPage->SetPageType(TDynamicDirCachePage::EUnknown);
       
  1109 		--iUnlockedQCount;
       
  1110 		}
       
  1111 	else
       
  1112 		{
       
  1113 		ASSERT(0);
       
  1114 		return KErrArgument;
       
  1115 		}
       
  1116 	return KErrNone;
       
  1117 	}
       
  1118 
       
  1119 /**
       
  1120 Insert a page to the first position of locked queue or unlocked queue.
       
  1121 @param	aPage	the pointer of the page to be inserted.
       
  1122 @param	aType	the type of the queue to be inserted.
       
  1123 @return	TInt	KErrArgument if aPage is invalid, otherwise KErrNone.
       
  1124 */
       
  1125 TInt CDynamicDirCache::AddFirstOntoQueue(TDynamicDirCachePage* aPage, TDynamicDirCachePage::TPageType aType)
       
  1126 	{
       
  1127 	ASSERT(aPage);
       
  1128 	if (!aPage)
       
  1129 		return KErrArgument;
       
  1130 
       
  1131 	// page must be dequed first or it is active page
       
  1132 	if (aPage->iType != TDynamicDirCachePage::EActivePage && aPage->iType != TDynamicDirCachePage::EUnknown)
       
  1133 		{
       
  1134 		ASSERT(0);
       
  1135 		return KErrArgument;
       
  1136 		}
       
  1137 
       
  1138 	if (aType == TDynamicDirCachePage::ELocked)
       
  1139 		{
       
  1140 		iLockedQ.AddFirst(*aPage);
       
  1141 		aPage->SetPageType(TDynamicDirCachePage::ELocked);
       
  1142 		++iLockedQCount;
       
  1143 		}
       
  1144 	else if (aType == TDynamicDirCachePage::EUnlocked)
       
  1145 		{
       
  1146 		iUnlockedQ.AddFirst(*aPage);
       
  1147 		aPage->SetPageType(TDynamicDirCachePage::EUnlocked);
       
  1148 		++iUnlockedQCount;
       
  1149 		}
       
  1150 	else
       
  1151 		{
       
  1152 		ASSERT(0);
       
  1153 		return KErrArgument;
       
  1154 		}
       
  1155 
       
  1156 	return KErrNone;
       
  1157 	}
       
  1158 
       
  1159 /**
       
  1160 Remove a page from the lookup table, indexed by the starting media address of the page content.
       
  1161 @param	aPagePos	the starting media position of the page to be removed.
       
  1162 */
       
  1163 TInt CDynamicDirCache::LookupTblRemove(TInt64 aPagePos)
       
  1164 	{
       
  1165 	if (aPagePos == 0)
       
  1166 		{
       
  1167 		return KErrNone;
       
  1168 		}
       
  1169 
       
  1170 	TInt r = iLookupTable.Remove(TLookupEntry(aPagePos, 0, NULL));
       
  1171 	return r;
       
  1172 	}
       
  1173 
       
  1174 /**
       
  1175 Insert a page to the lookup table, indexed by the starting media address of the page content.
       
  1176 @param	aPagePos	the starting media position of the page to be inserted.
       
  1177 */
       
  1178 TInt CDynamicDirCache::LookupTblAdd(TDynamicDirCachePage* aPage)
       
  1179 	{
       
  1180 	ASSERT(aPage);
       
  1181 	if (!aPage)
       
  1182 		return KErrArgument;
       
  1183 
       
  1184 	if (aPage->StartPos() == 0)
       
  1185 		{
       
  1186 		return KErrNone;
       
  1187 		}
       
  1188 
       
  1189 	TInt r = iLookupTable.Insert(TLookupEntry(aPage->StartPos(), iPageSizeInBytes, aPage));
       
  1190 	return r;
       
  1191 	}
       
  1192 
       
  1193 /**
       
  1194 Reset the media address of the page to 0, also invalidate the page.
       
  1195 @param	aPage	the pointer of the page to be reset.
       
  1196 */
       
  1197 TInt CDynamicDirCache::ResetPagePos(TDynamicDirCachePage* aPage)
       
  1198 	{
       
  1199 	ASSERT(aPage);
       
  1200 	if (!aPage)
       
  1201 		return KErrArgument;
       
  1202 
       
  1203 	aPage->ResetPos();
       
  1204 	return KErrNone;
       
  1205 	}
       
  1206 
       
  1207 /**
       
  1208 Search the lookup table to find the page start with a specific media address.
       
  1209 @param	aPos	the starting media address to be searched.
       
  1210 */
       
  1211 TDynamicDirCachePage* CDynamicDirCache::LookupTblFind(TInt64 aPos)
       
  1212 	{
       
  1213 	if (aPos == 0)
       
  1214 		{
       
  1215 		ASSERT(0);
       
  1216 		return NULL;
       
  1217 		}
       
  1218 
       
  1219 	TLookupEntry* entry = iLookupTable.Find(TLookupEntry(aPos, 0, NULL));
       
  1220 	if(entry)
       
  1221 		{
       
  1222 		ASSERT(entry->iPage->IsValid());
       
  1223 		return entry->iPage;
       
  1224 		}
       
  1225 
       
  1226 	return NULL;
       
  1227 	}