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