userlibandfileserver/fileserver/sfat/sl_cache.cpp
changeset 9 96e5fb8b040d
equal deleted inserted replaced
-1:000000000000 9:96e5fb8b040d
       
     1 // Copyright (c) 1996-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_cache.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "sl_std.h"
       
    19 #include "sl_cache.h"
       
    20 
       
    21 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
       
    22 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
       
    23 //!!
       
    24 //!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
       
    25 //!!
       
    26 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
       
    27 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
       
    28 
       
    29 //---------------------------------------------------------------------------------------------------------------------------------
       
    30 
       
    31 /**
       
    32     CWTCachePage factory function.    
       
    33     @param  aPageSizeLog2 Log2(cache page size in bytes)
       
    34     @return a pointer to the created object.
       
    35 */
       
    36 CWTCachePage* CWTCachePage::NewL(TUint32 aPageSizeLog2)
       
    37     {
       
    38     CWTCachePage* pSelf = new (ELeave)CWTCachePage;
       
    39     pSelf->ConstructL(aPageSizeLog2);
       
    40 
       
    41     return pSelf;
       
    42     }
       
    43 
       
    44 /**
       
    45     2nd stage constructor.
       
    46     @param  aPageSizeLog2 Log2(cache page size in bytes)
       
    47 */
       
    48 void CWTCachePage::ConstructL(TUint32 aPageSizeLog2)
       
    49     {
       
    50     iData.CreateMaxL(1 << aPageSizeLog2);
       
    51     }
       
    52 
       
    53 CWTCachePage::CWTCachePage()
       
    54     {
       
    55     iStartPos = 0xDeadDeadul;
       
    56     iValid  = 0;
       
    57     }
       
    58 
       
    59 CWTCachePage::~CWTCachePage() 
       
    60     { 
       
    61     iData.Close(); 
       
    62     }
       
    63 
       
    64 
       
    65 
       
    66 //---------------------------------------------------------------------------------------------------------------------------------
       
    67 
       
    68 CMediaWTCache::CMediaWTCache(TFatDriveInterface& aDrive)
       
    69           :iDrive(aDrive), iPageSizeLog2(0), iAllPagesValid(EFalse)
       
    70     {
       
    71     iCacheDisabled = EFalse;
       
    72     iCacheBasePos  = 0; 
       
    73     }
       
    74 
       
    75 CMediaWTCache::~CMediaWTCache()
       
    76     {
       
    77     //-- delete pages
       
    78     TInt cnt = iPages.Count();
       
    79     while(cnt--)
       
    80         {
       
    81         delete iPages[cnt];
       
    82         }
       
    83 
       
    84     iPages.Close();
       
    85     }
       
    86 
       
    87 
       
    88 /**
       
    89     Directory cache factory function.
       
    90 
       
    91     @param  aDrive  reference to the driver for media access.
       
    92     @param  aNumPages     number of cache pages to be created
       
    93     @param  aPageSizeLog2 Log2 of the page size in bytes
       
    94     
       
    95     @return a pointer to the created object.
       
    96 */
       
    97 CMediaWTCache* CMediaWTCache::NewL(TFatDriveInterface& aDrive, TUint32 aNumPages, TUint32 aPageSizeLog2)
       
    98     {
       
    99 #ifndef ENABLE_DEDICATED_DIR_CACHE    
       
   100     //-- dedicated directory cache isn't enabled
       
   101     (void)aDrive; //-- supress compiler's warning
       
   102     (void)aClusterSizeLog2;
       
   103     return NULL;
       
   104 #else    
       
   105 
       
   106     //-- dedicated directory cache is enabled, create it
       
   107     ASSERT(aPageSizeLog2);
       
   108     ASSERT(aNumPages);
       
   109 
       
   110     CMediaWTCache* pSelf = new (ELeave) CMediaWTCache(aDrive);
       
   111     
       
   112     CleanupStack::PushL(pSelf);
       
   113     pSelf->ConstructL(aNumPages, aPageSizeLog2);
       
   114     CleanupStack::Pop();
       
   115 
       
   116     return pSelf;
       
   117 
       
   118 #endif
       
   119     }
       
   120 
       
   121 /**
       
   122     2nd stage constructor.
       
   123     @param  aNumPages number of pages in the directory cache.
       
   124     @param  aPageSizeLog2 Log2(single cache page size in bytes)
       
   125 */
       
   126 void CMediaWTCache::ConstructL(TUint32 aNumPages, TUint32 aPageSizeLog2)
       
   127     {
       
   128     ASSERT(aNumPages && aPageSizeLog2);
       
   129     
       
   130     __PRINT2(_L("#CMediaWTCache::CreateL() Pages=%d, PageSize=%d"), aNumPages, 1<<aPageSizeLog2);
       
   131     
       
   132     iPageSizeLog2 = aPageSizeLog2; 
       
   133 
       
   134     //-- create cache pages
       
   135     for(TUint cnt=0; cnt<aNumPages; ++cnt)
       
   136         {
       
   137         CWTCachePage* pPage = CWTCachePage::NewL(aPageSizeLog2);
       
   138         iPages.Append(pPage);
       
   139         }
       
   140 
       
   141     InvalidateCache();  
       
   142     }
       
   143 
       
   144 
       
   145 /**
       
   146     @return size of the cache in bytes. Can be 0.
       
   147 */
       
   148 TUint32 CMediaWTCache::CacheSizeInBytes() const
       
   149     {
       
   150     const TUint32 cacheSz = iPages.Count() << iPageSizeLog2; //-- Page size is always power of 2
       
   151     return cacheSz;
       
   152     }
       
   153 
       
   154 /**
       
   155 Implementation of pure virtual function.
       
   156 @see MWTCacheInterface::MakePageMRU()
       
   157 */
       
   158 void CMediaWTCache::MakePageMRU(TInt64 /*aPos*/)
       
   159     {
       
   160     return;
       
   161     }
       
   162 
       
   163 /**
       
   164 Implementation of pure virtual function.
       
   165 @see MWTCacheInterface::PageSizeInBytesLog2()
       
   166 */
       
   167 TUint32 CMediaWTCache::PageSizeInBytesLog2() const
       
   168     {
       
   169     return iPageSizeLog2;
       
   170     }
       
   171 
       
   172 /**
       
   173     Control method.
       
   174 
       
   175     @param  aFunction   control function
       
   176     @param  aParam1     just arbitrary parameter 
       
   177     @param  aParam2     just arbitrary parameter 
       
   178     @return Standard error code.
       
   179 */
       
   180 
       
   181 TInt CMediaWTCache::Control(TUint32 aFunction, TUint32 aParam1, TAny* /*aParam2*/)
       
   182     {
       
   183     TInt nRes = KErrNotSupported;
       
   184 
       
   185 #ifdef _DEBUG
       
   186     switch(aFunction)
       
   187         {
       
   188         //-- disable / enable cache, for debug
       
   189         //-- if aParam1 !=0 cache will be disabled, enabled otherwise
       
   190         case EDisableCache: 
       
   191             iCacheDisabled = aParam1 ? 1 : 0;
       
   192             nRes = KErrNone;
       
   193         break;
       
   194 
       
   195         case EDumpCache:
       
   196         break;
       
   197            
       
   198         case ECacheInfo:
       
   199         break;
       
   200    
       
   201         default:
       
   202             __PRINT1(_L("CMediaWTCache::Control() invalid function: %d"), aFunction);
       
   203             ASSERT(0);
       
   204         break;
       
   205         }
       
   206 #else
       
   207     (void)aFunction; //-- supress warnings
       
   208     (void)aParam1;
       
   209     User::Invariant(); //-- don't call this method in release build
       
   210 #endif //_DEBUG   
       
   211     
       
   212     return nRes;
       
   213     }
       
   214 
       
   215 //-------------------------------------------------------------------------------------
       
   216 /**
       
   217     Invalidate whole cache
       
   218 */
       
   219 void CMediaWTCache::InvalidateCache(void)
       
   220     {
       
   221     const TUint nPages = iPages.Count();    
       
   222     for(TUint i=0; i<nPages; ++i)
       
   223         {
       
   224         iPages[i]->iValid=EFalse;
       
   225         }
       
   226 
       
   227     iAllPagesValid = EFalse;
       
   228     }
       
   229 
       
   230 //-------------------------------------------------------------------------------------
       
   231 /** 
       
   232     invalidate a single cache page if the aPos is cached (belongs to some page)
       
   233     If the cache user wants to invalidate some media address range, it will have to calculate 
       
   234     pages positions itself. The best way to do this - is to write another method that takes lenght of the 
       
   235     region being invalidated. 
       
   236 
       
   237     @param aPos media position. If it is cached, the corresponding single cache page will be marked as invalid
       
   238 */
       
   239 void CMediaWTCache::InvalidateCachePage(TUint64 aPos)
       
   240     {
       
   241     const TUint nPages = iPages.Count();    
       
   242     for(TUint i=0; i<nPages; ++i)
       
   243         {
       
   244         if( iPages[i]->PosCached(aPos))  
       
   245             {
       
   246             iPages[i]->iValid=EFalse;
       
   247             iAllPagesValid = EFalse;
       
   248             break;
       
   249             }
       
   250         }
       
   251 
       
   252     }
       
   253 
       
   254 //-------------------------------------------------------------------------------------
       
   255 
       
   256 /**
       
   257     Find cache page by given media position.
       
   258     
       
   259     @param  aPos    linear media position
       
   260     @return positive cache page number or -1 if no pages containing data at aPos found.
       
   261 */
       
   262 TInt CMediaWTCache::FindPageByPos(TInt64 aPos) const
       
   263     {
       
   264     const TUint nPages = iPages.Count();    
       
   265     for(TUint i=0; i<nPages; ++i)
       
   266         {
       
   267         if( iPages[i]->PosCached(aPos))  
       
   268             return i; 
       
   269         }
       
   270 
       
   271     return KErrNotFound;
       
   272     }
       
   273 
       
   274 /**
       
   275     Push given page aPageNo to the 1st position in the pages array. Used for LRU mechanism
       
   276     
       
   277     @param  aPageNo page number to be made LRU
       
   278 */
       
   279 void CMediaWTCache::MakePageLRU(TInt aPageNo)
       
   280     {
       
   281     ASSERT(aPageNo >=0);
       
   282 
       
   283     if(aPageNo <= 0)
       
   284         return; //-- nothing to do
       
   285     
       
   286     const TInt nPages = iPages.Count();
       
   287     ASSERT(aPageNo < nPages);
       
   288 
       
   289     if(aPageNo < nPages)
       
   290         {
       
   291         CWTCachePage* pPage=iPages[aPageNo];
       
   292     
       
   293         iPages.Remove(aPageNo);
       
   294         iPages.Insert(pPage,0); //-- insert the pointer to the 1st position in the array
       
   295         ASSERT(nPages == iPages.Count());
       
   296         }
       
   297     }
       
   298 
       
   299 /*
       
   300     Find a spare page or evict the last from LRU list
       
   301     
       
   302     @return page number
       
   303 */
       
   304 TUint32  CMediaWTCache::GrabPage() const
       
   305     {
       
   306     const TUint nPages = iPages.Count();
       
   307 
       
   308     if(!iAllPagesValid)
       
   309         {//-- try to find unused cache page
       
   310         for(TUint i=0; i<nPages; ++i)
       
   311             {
       
   312             if(! iPages[i]->iValid)
       
   313                 return i; //-- found unused page
       
   314             }
       
   315         }
       
   316 
       
   317     //-- no spare pages, evict the last one, it shall be last used
       
   318     iAllPagesValid = ETrue;
       
   319     return nPages-1;
       
   320     }
       
   321 
       
   322 /*
       
   323     Find a spare page or evict the last from LRU list, then read data to this page from media starting from aPos
       
   324     
       
   325     @param  aPos    media linear position from where the data will be read to the page
       
   326     @return cache page number
       
   327 */
       
   328 TUint32 CMediaWTCache::GrabReadPageL(TInt64 aPos)
       
   329     {
       
   330     //-- find a spare or page to evict
       
   331     TUint nPage = GrabPage();
       
   332     CWTCachePage& page = *iPages[nPage]; 
       
   333 
       
   334     //-- read data to this page
       
   335     page.iStartPos = CalcPageStartPos(aPos);
       
   336     
       
   337     __PRINT4(_L("#CMediaWTCache::GrabReadPageL() Reading page:%d, Pos=0x%x, PageStartPos=0x%x, page=0x%X"),nPage, (TUint32)aPos, (TUint32)page.iStartPos, iPages[nPage]);
       
   338         
       
   339     const TInt nErr = iDrive.ReadNonCritical(page.iStartPos, PageSize(), page.iData);
       
   340     if(nErr !=KErrNone)
       
   341         {//-- some serious problem occured during reading, invalidate cache.
       
   342         InvalidateCache();
       
   343         User::Leave(nErr);
       
   344         }
       
   345     
       
   346     page.iValid = ETrue;
       
   347 
       
   348     return nPage;
       
   349     }
       
   350 
       
   351 /**
       
   352     Try to find the page with cached data at "aPos" media position.
       
   353     If such page found, returns its number, otherwise takes least recently used page and reads data there.
       
   354     
       
   355     @param  aPos    media linear position to find in the cache
       
   356     @return cache page number
       
   357 
       
   358 */
       
   359 TUint32 CMediaWTCache::FindOrGrabReadPageL(TInt64 aPos)
       
   360     {
       
   361     //-- find out if aPos is in cache
       
   362     TInt nPage=FindPageByPos(aPos);
       
   363     
       
   364     if(nPage < 0)
       
   365         {//-- no page contains data to read
       
   366         nPage = GrabReadPageL(aPos); //-- find a spare page and read data into it
       
   367         }
       
   368 
       
   369     return nPage;
       
   370     }
       
   371 
       
   372 /**
       
   373     Finds out if the media position "aPosToSearch" is in the cache and returns cache page information in this case.
       
   374 
       
   375     @param  aPosToSearch    linear media position to lookup in the cache
       
   376     @param  aCachedPosStart if "aPosToSearch" is cached, here will be media position of this page start
       
   377     
       
   378     @return 0 if aPosToSearch isn't cached, otherwise  cache page size in bytes (see also aCachedPosStart).
       
   379 */
       
   380 TUint32 CMediaWTCache::PosCached(const TInt64& aPosToSearch, TInt64& aCachedPosStart)
       
   381     {
       
   382     TInt nPage = FindPageByPos(aPosToSearch);
       
   383     if(nPage <0 )
       
   384         return 0; //-- cache page containing aPos not found
       
   385 
       
   386     aCachedPosStart = iPages[nPage]->iStartPos;
       
   387     
       
   388     return PageSize();
       
   389     }
       
   390 
       
   391 /**
       
   392     Read data from the media through the directory cache.
       
   393     
       
   394     @param  aPos    linear media position to start reading with
       
   395     @param  aLength how many bytes to read
       
   396     @param  aDes    data will be placed there
       
   397 */
       
   398 void CMediaWTCache::ReadL(TInt64 aPos,TInt aLength,TDes8& aDes)
       
   399     {
       
   400     
       
   401 #ifdef _DEBUG
       
   402     if(iCacheDisabled)
       
   403         {//-- cache is disabled for debug purposes
       
   404         User::LeaveIfError(iDrive.ReadNonCritical(aPos, aLength, aDes));
       
   405         return;
       
   406         }
       
   407 #endif //_DEBUG
       
   408 
       
   409     const TUint32 PageSz = PageSize();//-- cache page size
       
   410 
       
   411     //-- find out if aPos is in cache. If not, find a spare page and read data there
       
   412     TInt nPage = FindOrGrabReadPageL(aPos);
       
   413     CWTCachePage* pPage = iPages[nPage];
       
   414 
       
   415     const TUint32 bytesToPageEnd = (TUint32)(pPage->iStartPos+PageSz - aPos); //-- number of bytes from aPos to the end of the page
       
   416 
       
   417 //    __PRINT5(_L("CMediaWTCache::ReadL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, aLength, pPage->iStartPos, PageSz, bytesToPageEnd);
       
   418     if((TUint32)aLength <= bytesToPageEnd) 
       
   419         {//-- the data section is in the cache page entirely, take data directly from the cache
       
   420         aDes.Copy(pPage->PtrInCachePage(aPos), aLength);
       
   421         }
       
   422     else
       
   423         {//-- Data to be read cross cache page boundary or probably we have more than 1 page to read
       
   424 
       
   425         TUint32 dataLen(aLength);   //-- current data length
       
   426         TInt64  currMediaPos(aPos); //-- current media position
       
   427 
       
   428         //-- 1. read data that are already in the current page
       
   429         aDes.Copy(pPage->PtrInCachePage(currMediaPos), bytesToPageEnd);
       
   430 
       
   431         dataLen -= bytesToPageEnd;
       
   432         currMediaPos += bytesToPageEnd;
       
   433 
       
   434         //-- 2. read whole pages of data
       
   435         while(dataLen >= PageSz)
       
   436             {
       
   437             nPage = FindOrGrabReadPageL(currMediaPos); //-- find out if currMediaPos is in cache. If not, find a spare page and read data there
       
   438             pPage = iPages[nPage];
       
   439 
       
   440             aDes.Append(pPage->PtrInCachePage(currMediaPos),PageSz);
       
   441         
       
   442             dataLen -= PageSz;
       
   443             currMediaPos += PageSz;
       
   444         
       
   445             MakePageLRU(nPage); //-- push the page to the top of the priority list
       
   446             }
       
   447 
       
   448         //-- 3. read the rest of the data
       
   449         if(dataLen >0)
       
   450             {
       
   451             nPage = FindOrGrabReadPageL(currMediaPos); //-- find out if currMediaPos is in cache. If not, find a spare page and read data there
       
   452             pPage = iPages[nPage];
       
   453 
       
   454             aDes.Append(pPage->PtrInCachePage(currMediaPos), dataLen);
       
   455             }
       
   456 
       
   457         } //else((TUint32)aLength <= bytesToPageEnd) 
       
   458 
       
   459 
       
   460     MakePageLRU(nPage); //-- push the page to the top of the priority list
       
   461     
       
   462     }
       
   463 
       
   464 /**
       
   465     Write data to the media through the directory cache.
       
   466     
       
   467     @param  aPos    linear media position to start writing with
       
   468     @param  aDes    data to write
       
   469 */
       
   470 void CMediaWTCache::WriteL(TInt64 aPos,const TDesC8& aDes)
       
   471     {
       
   472 
       
   473 #ifdef _DEBUG
       
   474     if(iCacheDisabled)
       
   475         {//-- cache is disabled for debug purposes
       
   476         User::LeaveIfError(iDrive.WriteCritical(aPos,aDes));
       
   477         return;
       
   478         }
       
   479 #endif //_DEBUG
       
   480 
       
   481           TUint32 dataLen = aDes.Size();
       
   482     const TUint8* pData   = aDes.Ptr();
       
   483     const TUint32 PageSz  = PageSize(); //-- cache page size
       
   484 
       
   485     //-- find out if aPos is in cache. If not, find a spare page and read data there
       
   486     TInt nPage = FindOrGrabReadPageL(aPos);
       
   487     CWTCachePage* pPage = iPages[nPage];
       
   488 
       
   489     const TUint32 bytesToPageEnd = (TUint32)(pPage->iStartPos+PageSize() - aPos); //-- number of bytes from aPos to the end of the page
       
   490 //    __PRINT5(_L("CMediaWTCache::WriteL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, dataLen, pPage->iStartPos, PageSz, bytesToPageEnd);
       
   491     if(dataLen <= bytesToPageEnd)
       
   492         {//-- data section completely fits to the cache page
       
   493         Mem::Copy(pPage->PtrInCachePage(aPos), pData, dataLen);   //-- update cache
       
   494         }
       
   495     else
       
   496         {//-- Data to be written cross cache page boundary or probably we have more than 1 page to write
       
   497 
       
   498         TInt64  currMediaPos(aPos); //-- current media position
       
   499 
       
   500         //-- 1. update the current page
       
   501         Mem::Copy(pPage->PtrInCachePage(currMediaPos), pData, bytesToPageEnd);
       
   502 
       
   503         pData += bytesToPageEnd;
       
   504         currMediaPos += bytesToPageEnd;
       
   505         dataLen -= bytesToPageEnd;
       
   506 
       
   507         //-- 2. write whole pages of data to the cache
       
   508         while(dataLen >= PageSz)
       
   509             {
       
   510             nPage = FindPageByPos(currMediaPos); //-- ?? shall we read data there ??
       
   511             if(nPage >=0)
       
   512                 {
       
   513                 pPage = iPages[nPage];
       
   514                 Mem::Copy(pPage->PtrInCachePage(currMediaPos), pData, PageSz);
       
   515                 MakePageLRU(nPage); //-- push the page to the top of the priority list
       
   516                 }
       
   517             else
       
   518                 nPage=0;
       
   519 
       
   520             pData += PageSz;
       
   521             currMediaPos += PageSz;
       
   522             dataLen -= PageSz;
       
   523             }
       
   524 
       
   525         //-- 3. write the rest of the data
       
   526         if(dataLen)
       
   527             {
       
   528             nPage = FindOrGrabReadPageL(currMediaPos); //-- find out if currMediaPos is in cache. If not, find a spare page and read data there
       
   529             pPage = iPages[nPage];
       
   530 
       
   531             Mem::Copy(pPage->PtrInCachePage(currMediaPos), pData, dataLen);
       
   532             }
       
   533 
       
   534         }// else(dataLen <= bytesToPageEnd)
       
   535 
       
   536     
       
   537     //-- write data to the media
       
   538     const TInt nErr = iDrive.WriteCritical(aPos,aDes); 
       
   539     if(nErr != KErrNone)
       
   540         {//-- some serious problem occured during writing, invalidate cache.
       
   541         InvalidateCache();
       
   542         User::Leave(nErr);
       
   543         }
       
   544 
       
   545     MakePageLRU(nPage); //-- push the page to the top of the priority list
       
   546     }
       
   547 
       
   548 
       
   549 
       
   550 
       
   551 
       
   552 
       
   553 
       
   554 
       
   555 
       
   556 
       
   557 
       
   558 
       
   559 
       
   560 
       
   561 
       
   562 
       
   563