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