os/kernelhwsrv/userlibandfileserver/fileserver/sfat32/sl_cache.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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(TDriveInterface& 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(TDriveInterface& 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