os/kernelhwsrv/userlibandfileserver/fileserver/sfat/sl_cache.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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