userlibandfileserver/fileserver/sfat32/sl_fatcache32.cpp
changeset 0 a41df078684a
child 109 b3a1d9898418
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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\sfat32\sl_fatcache32.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "sl_std.h"
       
    19 #include "sl_fatcache32.h"
       
    20 
       
    21 /**
       
    22     @file
       
    23     Various FAT32 caches implementation
       
    24 */
       
    25 
       
    26 
       
    27 
       
    28 //#################################################################################################################################
       
    29 //# CFat32LruCache implementation
       
    30 //#################################################################################################################################
       
    31 
       
    32 //-----------------------------------------------------------------------------
       
    33 CFat32LruCache::CFat32LruCache()
       
    34                :CFatPagedCacheBase(), iPageList(_FOFF(CFat32LruCachePage, iLink))
       
    35     {
       
    36     }
       
    37 
       
    38 //-----------------------------------------------------------------------------
       
    39 /**
       
    40     FAT32 LRU cache factory function.
       
    41     @param  aOwner              pointer to the owning FAT mount
       
    42     @param  aMaxMemSize         maximal size of the memory the cache can use, bytes
       
    43     @param  aRdGranularityLog2  Log2(read granularity)
       
    44     @param  aWrGranularityLog2  Log2(write granularity)
       
    45 
       
    46     @return pointer to the constructed object.
       
    47 */
       
    48 CFat32LruCache* CFat32LruCache::NewL(CFatMountCB* aOwner, TUint32 aMaxMemSize, TUint32 aRdGranularityLog2, TUint32 aWrGranularityLog2)
       
    49     {
       
    50     __PRINT(_L("#-CFat32LruCache::NewL()"));
       
    51     CFat32LruCache* pSelf = NULL;
       
    52     pSelf = new (ELeave) CFat32LruCache;
       
    53 
       
    54     CleanupStack::PushL(pSelf);
       
    55     pSelf->InitialiseL(aOwner, aMaxMemSize, aRdGranularityLog2, aWrGranularityLog2);
       
    56     CleanupStack::Pop();
       
    57     
       
    58     return pSelf;
       
    59     }
       
    60 
       
    61 //-----------------------------------------------------------------------------
       
    62 /** 
       
    63     @return pointer to the CFatBitCache interface. 
       
    64 */
       
    65 CFatBitCache* CFat32LruCache::BitCacheInterface() 
       
    66     {
       
    67     return iBitCache;
       
    68     }  
       
    69 
       
    70 //-----------------------------------------------------------------------------
       
    71 
       
    72 /**
       
    73     FAT32 LRU cache initialisation.
       
    74 
       
    75     @param  aOwner              pointer to the owning FAT mount
       
    76     @param  aMaxMemSize         maximal size of the memory the cache can use, bytes
       
    77     @param  aRdGranularityLog2  Log2(read granularity)
       
    78     @param  aWrGranularityLog2  Log2(write granularity)
       
    79 
       
    80     @return pointer to the constructed object.
       
    81 */
       
    82 void  CFat32LruCache::InitialiseL(CFatMountCB* aOwner, TUint32 aMaxMemSize, TUint32 aRdGranularityLog2, TUint32 aWrGranularityLog2)
       
    83     {
       
    84     const TUint32 KReadGranularity = Pow2(aRdGranularityLog2);
       
    85     const TUint32 KWriteGranularity = Pow2(aWrGranularityLog2);
       
    86 
       
    87     __PRINT3(_L("#-CFat32LruCache::InitialiseL MaxMem:%u, RdGr:%d, WrGr:%d"),aMaxMemSize, KReadGranularity, KWriteGranularity);
       
    88     (void)KReadGranularity;
       
    89     (void)KWriteGranularity;
       
    90 
       
    91 
       
    92     const TBool bParamsValid = (aRdGranularityLog2 >= aWrGranularityLog2) && (aWrGranularityLog2 >= KDefSectorSzLog2) && (aMaxMemSize > KReadGranularity);
       
    93     __ASSERT_ALWAYS(bParamsValid, Fault(EFatCache_BadGranularity));  
       
    94    
       
    95     CFatPagedCacheBase::InitialiseL(aOwner);
       
    96     
       
    97     ASSERT(FatType() == EFat32);
       
    98     
       
    99     //-- according to the FAT32 specs, FAT32 min size is 65526 entries or 262104 bytes.
       
   100     //-- It's possible to incorrectly format a small volume to FAT32, it shall be accessible read-only.
       
   101     if(aMaxMemSize > FatSize()) 
       
   102         {//-- strange situation, memory allocated for LRU cache is enough to cache whole FAT32
       
   103         __PRINT(_L("#-CFat32LruCache::InitialiseL warning: LRU cache becomes fixed! (too much memory allowed)"));
       
   104         aMaxMemSize = FatSize();
       
   105         }
       
   106 
       
   107     //-- LRU cache page size is (2^aRdGranularityLog2) bytes and consists of 2^(aRdGranularityLog2-aWrGranularity) sectors.
       
   108     iPageSizeLog2 = aRdGranularityLog2;
       
   109     iSectorSizeLog2 = aWrGranularityLog2; //-- Log2(number of sectors in cache page)
       
   110 
       
   111     iMaxPages = aMaxMemSize / PageSize(); //-- maximal number of cache pages we can allocate
       
   112     iNumPagesAllocated = 0;
       
   113     
       
   114     __ASSERT_ALWAYS((iMaxPages > 1 && SectorsInPage() < KMaxSectorsInPage), Fault(EFatCache_BadGranularity));
       
   115 
       
   116     //-- obtain maximal number of entries in the table
       
   117     if(aOwner->UsableClusters() < 1)
       
   118         {
       
   119         ASSERT(0);
       
   120         User::Leave(KErrCorrupt);
       
   121         }
       
   122 
       
   123     iMaxFatEntries = aOwner->UsableClusters()+KFatFirstSearchCluster; //-- FAT[0] & FAT[1] are not in use
       
   124 
       
   125     //-- create FAT bit supercache if it is enabled in config
       
   126     ASSERT(!iBitCache);
       
   127     if(aOwner->FatConfig().FAT32_UseBitSupercache())
       
   128         {
       
   129         iBitCache = CFatBitCache::New(*this);
       
   130         }
       
   131     else
       
   132         {
       
   133         __PRINT(_L("#++ !! Fat Bit Supercache is disabled in config !!"));
       
   134         }
       
   135 
       
   136     }
       
   137 
       
   138 //-----------------------------------------------------------------------------
       
   139 /**
       
   140     Close the cache and deallocate its memory.
       
   141     @param  aDiscardDirtyData if ETrue, will ignore dirty data. If EFalse, will panic on atempt to close dirty cache.  
       
   142 */
       
   143 void CFat32LruCache::Close(TBool aDiscardDirtyData)
       
   144     {
       
   145     __PRINT1(_L("#-CFat32LruCache::Close(%d)"), aDiscardDirtyData);
       
   146     
       
   147     //-- delete FAT bit supercache if present
       
   148     delete iBitCache;
       
   149     iBitCache=NULL;
       
   150 
       
   151 
       
   152     //-- delete existing cache pages
       
   153     TPageIterator itr(iPageList);
       
   154 
       
   155     for(;;)
       
   156         {
       
   157         CFat32LruCachePage* pPage = itr++;
       
   158         if(!pPage) 
       
   159             break;
       
   160 
       
   161         pPage->iLink.Deque(); //-- remove page from the list
       
   162         
       
   163         if(pPage->IsDirty())
       
   164             {//-- trying to destroy the cache that has dirty pages
       
   165             __PRINT1(_L("#-CFat32LruCache::Close() The page is dirty! Start idx:%d"), pPage->StartFatIndex());
       
   166             if(!aDiscardDirtyData)
       
   167                 {
       
   168                 Fault(EFatCache_DiscardingDirtyData);  
       
   169                 }
       
   170             //-- ignore this fact if requested.
       
   171             }
       
   172 
       
   173         delete pPage;
       
   174         --iNumPagesAllocated;
       
   175         }
       
   176 
       
   177     SetDirty(EFalse);
       
   178     ASSERT(!iNumPagesAllocated);
       
   179     }
       
   180 
       
   181 
       
   182 //-----------------------------------------------------------------------------
       
   183 /**
       
   184     Tries to read FAT entry from the cache. If the entry at aFatIndex is not cached, does nothing and returns EFalse.
       
   185     If finds the cache page that contains entry at index "aFatIndex", reads it and returns ETrue.
       
   186 
       
   187     @param  aFatIndex  FAT entry index within FAT table
       
   188     @param  aFatEntry  on success it will contain FAT entry value
       
   189     @return ETrue if the entry has been read
       
   190             EFalse if index aFatIndex isn't cached
       
   191 */
       
   192 TBool CFat32LruCache::ReadCachedEntryL(TUint32 aFatIndex, TFat32Entry& aResult)
       
   193     {
       
   194     //-- iterate through LRU list looking if the entry is cached.
       
   195     TPageIterator itr(iPageList);
       
   196 
       
   197     for(;;)
       
   198         {
       
   199         CFat32LruCachePage* pPage = itr++;
       
   200         if(!pPage) 
       
   201             break;
       
   202 
       
   203         if(pPage->ReadCachedEntryL(aFatIndex, aResult))
       
   204             {//-- found entry in some cache page. Make this page LRU
       
   205             if(!iPageList.IsFirst(pPage))
       
   206                 {
       
   207                 pPage->iLink.Deque();
       
   208                 iPageList.AddFirst(*pPage);
       
   209                 }
       
   210             return ETrue; 
       
   211             }
       
   212         }
       
   213 
       
   214     return EFalse; //-- the entry is not cached
       
   215     }
       
   216 
       
   217 //-----------------------------------------------------------------------------
       
   218 /**
       
   219     Tries to write FAT entry to the cache. If the entry at aFatIndex is not cached, does nothing and returns EFalse.
       
   220     If finds the cache page that contains entry at index "aFatIndex", overwrites it and returns ETrue
       
   221 
       
   222     @param  aFatIndex  FAT entry index within FAT table
       
   223     @param  aFatEntry  new FAT entry value
       
   224     @return ETrue if the entry has been overwritten
       
   225             EFalse if index aFatIndex isn't cached
       
   226 */
       
   227 TBool CFat32LruCache::WriteCachedEntryL(TUint32 aFatIndex, TFat32Entry aFatEntry)
       
   228     {
       
   229     //-- iterate through LRU list looking if the entry is cached.
       
   230     TPageIterator itr(iPageList);
       
   231 
       
   232     for(;;)
       
   233         {
       
   234         CFat32LruCachePage* pPage = itr++;
       
   235         if(!pPage) 
       
   236             break;
       
   237 
       
   238         if(pPage->WriteCachedEntryL(aFatIndex, aFatEntry))
       
   239             {//-- the entry was cached and modified now. Make this page LRU
       
   240             if(!iPageList.IsFirst(pPage))
       
   241                 {
       
   242                 pPage->iLink.Deque();
       
   243                 iPageList.AddFirst(*pPage);
       
   244                 }
       
   245             return ETrue; 
       
   246             }
       
   247         }
       
   248     
       
   249     return EFalse; //-- the entry is not cached
       
   250     }
       
   251 
       
   252 //-----------------------------------------------------------------------------
       
   253 /**
       
   254     Get a spare page. This function can either allocate a page if memory limit isn't reached yet
       
   255     or find the least recently used (in the end of the LRU list) and evict it.
       
   256     
       
   257     @return pointer to the cache page to use, it will be insertet to the beginning of the LRU list
       
   258 */
       
   259 CFat32LruCachePage* CFat32LruCache::DoGetSpareCachePageL()
       
   260     {
       
   261     CFat32LruCachePage* pPage=NULL;
       
   262 
       
   263     if(iNumPagesAllocated < iMaxPages)
       
   264         {//-- we still can allocate a page
       
   265     
       
   266         pPage = CFat32LruCachePage::NewL(*this);
       
   267         ++iNumPagesAllocated;
       
   268         iPageList.AddFirst(*pPage); //-- insert the page into the beginning of LRU list
       
   269         return pPage;
       
   270         }
       
   271 
       
   272     //-- all pages are already allocated, evict the last recently used and remove it from the list
       
   273     pPage = iPageList.Last();   //-- least recently used page, last in the list
       
   274     pPage->iLink.Deque();       //-- remove it from the LRU list
       
   275     iPageList.AddFirst(*pPage); //-- insert the page into the beginning of LRU list
       
   276 
       
   277     //__PRINT1(_L("#-CFat32LruCache::DoGetSpareCachePageL() page @FAT idx:%d evicted"), pPage->StartFatIndex());
       
   278     
       
   279     //-- flush the page, writing its data to all copies of FAT, to FAT1, then to FAT2 etc.
       
   280     ASSERT(NumFATs() >0);
       
   281     if(pPage->IsDirty())
       
   282         {
       
   283         //-- write page data to all copies of FAT
       
   284         for(iCurrentFatNo=0; iCurrentFatNo < NumFATs(); ++iCurrentFatNo)
       
   285             {
       
   286             const TBool keepDirty = iCurrentFatNo < (NumFATs()-1);
       
   287             pPage->FlushL(keepDirty);
       
   288             }
       
   289     
       
   290         iCurrentFatNo = KInvalidFatNo;
       
   291         }
       
   292 
       
   293     
       
   294     return pPage;
       
   295     }
       
   296 
       
   297 
       
   298 
       
   299 //-----------------------------------------------------------------------------
       
   300 /**
       
   301     Read FAT entry from the cache. 
       
   302 
       
   303     @param  aIndex FAT entry index to read
       
   304     @return FAT entry value at the index "aIndex"
       
   305 */
       
   306 TUint32 CFat32LruCache::ReadEntryL(TUint32 aIndex)
       
   307     {
       
   308 //    __PRINT1(_L("#-CFat32LruCache::ReadEntryL() FAT idx:%d"), aIndex);
       
   309 
       
   310     ASSERT(aIndex >= KFatFirstSearchCluster &&  aIndex < (FatSize() >> KFat32EntrySzLog2));
       
   311 
       
   312     //-- firstly try to locate required entry in cache
       
   313     TFat32Entry entry;
       
   314     if(ReadCachedEntryL(aIndex, entry))
       
   315         return entry; //-- the requested entry found in cache
       
   316 
       
   317     //-- No luck, get a spare cache page (it will be inserted to the head of the LRU list)
       
   318     CFat32LruCachePage* pPage = DoGetSpareCachePageL();
       
   319     ASSERT(pPage); 
       
   320 
       
   321     entry = pPage->ReadFromMediaL(aIndex); //-- read whole FAT page from the media
       
   322 
       
   323     return entry;
       
   324     }
       
   325 
       
   326 //-----------------------------------------------------------------------------
       
   327 /**
       
   328     Write FAT entry to the cache. 
       
   329     Appropriate FAT cache sector will be marked as "dirty" and will be eventually flushed to the media.
       
   330 
       
   331     @param  aIndex FAT entry index
       
   332     @param  aEntry FAT entry value
       
   333 */
       
   334 void CFat32LruCache::WriteEntryL(TUint32 aIndex, TUint32 aEntry)
       
   335     {
       
   336     //__PRINT2(_L("#-CFat32LruCache::WriteEntryL() FAT idx:%d, val:%d"), aIndex, aEntry);
       
   337 
       
   338     ASSERT(aIndex >= KFatFirstSearchCluster &&  aIndex < (FatSize() >> KFat32EntrySzLog2));
       
   339 
       
   340     SetDirty(ETrue);
       
   341 
       
   342     //-- 1. try to locate entry in the cache and overwrite it there if it is cached
       
   343     if(WriteCachedEntryL(aIndex, aEntry))
       
   344         return; //-- the entry in cache altered
       
   345     
       
   346     //-- 2. the entry isn't cached; find a spare cache page (it will be inserted to the head of the LRU list)
       
   347     CFat32LruCachePage* pPage = DoGetSpareCachePageL();
       
   348     ASSERT(pPage); 
       
   349     
       
   350     pPage->ReadFromMediaL(aIndex); //-- read whole FAT page from the media
       
   351 
       
   352 
       
   353     //-- 3. overwrite entry in cache
       
   354     TBool bRes = pPage->WriteCachedEntryL(aIndex, aEntry);
       
   355     ASSERT(bRes);
       
   356     (void)bRes;
       
   357     }
       
   358 
       
   359 //-----------------------------------------------------------------------------
       
   360 /**
       
   361     A debug method that asserts that the cache is really clean
       
   362 */
       
   363 void CFat32LruCache::AssertCacheReallyClean() 
       
   364     {
       
   365 #ifdef _DEBUG 
       
   366     
       
   367     TPageIterator itr(iPageList);
       
   368     for(;;)
       
   369         {//-- iterate through LRU list flushing pages into the current copy of FAT
       
   370         CFat32LruCachePage* pPage = itr++;
       
   371         
       
   372         if(!pPage) 
       
   373             break;
       
   374 
       
   375         if(pPage->IsDirty())
       
   376             {
       
   377             __PRINT(_L("#-CFat32LruCache::AssertCacheReallyClean()"));
       
   378             ASSERT(0);
       
   379             }
       
   380         }
       
   381 
       
   382 #endif   
       
   383     }
       
   384 
       
   385 //-----------------------------------------------------------------------------
       
   386 /**
       
   387     Flushes all dirty data to the media.
       
   388 */
       
   389 void CFat32LruCache::FlushL()
       
   390     {
       
   391     if(!IsDirty())
       
   392         {
       
   393         AssertCacheReallyClean();
       
   394         return;
       
   395         }
       
   396 
       
   397     //-- flush dirty data to all copies of FAT
       
   398     //-- all dirty pages will be written firstly to FAT1, then all of them will be written to FAT2 etc.
       
   399     for(iCurrentFatNo=0; iCurrentFatNo < NumFATs(); ++iCurrentFatNo)
       
   400         {
       
   401         TPageIterator itr(iPageList);
       
   402         for(;;)
       
   403             {//-- iterate through LRU list flushing pages into the current copy of FAT
       
   404             CFat32LruCachePage* pPage = itr++;
       
   405             if(!pPage) 
       
   406                 break;
       
   407 
       
   408             //-- we need to keep page dirty until it is flushed to the last copy of FAT table
       
   409             const TBool keepDirty = iCurrentFatNo < (NumFATs() - 1);
       
   410             pPage->FlushL(keepDirty);
       
   411             }
       
   412         }
       
   413    
       
   414     iCurrentFatNo = KInvalidFatNo;
       
   415    
       
   416     SetDirty(EFalse);
       
   417     }
       
   418 
       
   419 //-----------------------------------------------------------------------------
       
   420 
       
   421 /**
       
   422     Invalidate whole cache. All pages will be marked as invalid and will be re-read from the media on first access to them.
       
   423     @return always KErrNone
       
   424 */
       
   425 TInt CFat32LruCache::Invalidate()
       
   426     {
       
   427     __PRINT(_L("#-CFat32LruCache::Invalidate()"));
       
   428     const TBool bIgnoreDirtyData = CheckInvalidatingDirtyCache();
       
   429 
       
   430     //-- iterate through LRU list marking every page as invalid
       
   431     TPageIterator itr(iPageList);
       
   432     for(;;)
       
   433         {
       
   434         CFat32LruCachePage* pPage = itr++;
       
   435         if(!pPage) 
       
   436             break;
       
   437 
       
   438         pPage->Invalidate(bIgnoreDirtyData);
       
   439         }
       
   440 
       
   441     SetDirty(EFalse);
       
   442 
       
   443     return KErrNone;
       
   444     }
       
   445 
       
   446 
       
   447 //-----------------------------------------------------------------------------
       
   448 
       
   449 /**
       
   450     Invalidate FAT cache pages that contain FAT32 entries from aStartIndex to (aStartIndex+aNumEntries)
       
   451     These pages will be marked as invalid and will be re-read from the media on first access to them.
       
   452     
       
   453     @param  aStartIndex FAT start index of the region being invalidated
       
   454     @param  aNumEntries number of entries to invalidate
       
   455     @return always KErrNone
       
   456 */
       
   457 TInt CFat32LruCache::InvalidateRegion(TUint32 aStartIndex, TUint32 aNumEntries)
       
   458     {
       
   459     __PRINT2(_L("#-CFat32LruCache::InvalidateRegion() startIndex:%d, entries:%d"),aStartIndex, aNumEntries);
       
   460     ASSERT(aStartIndex >= KFatFirstSearchCluster &&  aStartIndex < (FatSize() >> KFat32EntrySzLog2));
       
   461 
       
   462     if(!aNumEntries)
       
   463         {
       
   464         ASSERT(0);
       
   465         return KErrNone;
       
   466         }
       
   467 
       
   468     const TBool bIgnoreDirtyData = CheckInvalidatingDirtyCache();
       
   469     const TUint KEntriesInPage = Pow2(PageSizeLog2() - KFat32EntrySzLog2);
       
   470     const TUint KLastIndex = aStartIndex+aNumEntries;
       
   471 
       
   472     TBool bCacheIsStillDirty = EFalse; //-- ETrue if the cache is still dirty after invalidating its region
       
   473     
       
   474     for(TUint currIndex = aStartIndex; currIndex < KLastIndex; currIndex+=KEntriesInPage)
       
   475         {
       
   476         TPageIterator itr(iPageList);
       
   477         for(;;)
       
   478             {//-- iterate through all pages, invalidating required
       
   479             CFat32LruCachePage* pPage = itr++;
       
   480             if(!pPage) 
       
   481                 break;
       
   482 
       
   483             if(pPage->IsEntryCached(currIndex))
       
   484                 {
       
   485                 pPage->Invalidate(bIgnoreDirtyData); 
       
   486                 }
       
   487             else if(pPage->IsDirty()) //-- invalid page can't be ditry.
       
   488                 {
       
   489                 bCacheIsStillDirty = ETrue; //-- we have at least 1 dirty page
       
   490                 }
       
   491             }
       
   492         }
       
   493 
       
   494     SetDirty(bCacheIsStillDirty);
       
   495     
       
   496     return KErrNone;
       
   497 }
       
   498 
       
   499 //-----------------------------------------------------------------------------
       
   500 
       
   501 
       
   502 
       
   503 /**
       
   504     Look for free FAT entry in the FAT sector that corresponds to the aFatEntryIndex.
       
   505     Search is performed in both directions, the right one has more priority (FAT cluster chain needs to grow right).
       
   506     See FindFreeEntryInCacheSector()
       
   507 */
       
   508 TBool CFat32LruCache::FindFreeEntryInCacheSectorL(TUint32& aFatEntryIndex)
       
   509     {
       
   510     if(ReadEntryL(aFatEntryIndex) == KSpareCluster)
       
   511         return ETrue;
       
   512     
       
   513     //-- look for free FAT entries in the FAT cache sector corresponting to the aStartIndex.
       
   514     //-- use the same approach as in CFatTable::FindClosestFreeClusterL()
       
   515     const TUint32 coeff = SectorSizeLog2()-KFat32EntrySzLog2;
       
   516     const TUint32 numEntriesInSector = Pow2(coeff); //-- number of FAT32 entries in FAT cache sector
       
   517 
       
   518     TUint32 MinIdx = (aFatEntryIndex >> coeff) << coeff;
       
   519     TUint32 MaxIdx = MinIdx+numEntriesInSector-1;
       
   520 
       
   521     if(MinIdx == 0)
       
   522         {//-- correct values if this is the first FAT sector; FAT[0] & FAT[1] are reserved
       
   523         MinIdx += KFatFirstSearchCluster;
       
   524         }
       
   525 
       
   526     //-- actual number of usable FAT entries can be less than deducted from number of FAT sectors.
       
   527     MaxIdx = Min(MaxIdx, iMaxFatEntries-1);
       
   528 
       
   529     //-- look in both directions starting from the aFatEntryIndex
       
   530     //-- but in one FAT cache page sector only
       
   531     TBool canGoRight = ETrue;
       
   532     TBool canGoLeft = ETrue;
       
   533     
       
   534     TUint32 rightIdx=aFatEntryIndex;
       
   535     TUint32 leftIdx=aFatEntryIndex;
       
   536 
       
   537     for(TUint i=0; i<numEntriesInSector; ++i)
       
   538         {
       
   539         if(canGoRight)
       
   540             {
       
   541             if(rightIdx < MaxIdx)
       
   542                 ++rightIdx;
       
   543             else
       
   544                 canGoRight = EFalse;
       
   545             }
       
   546 
       
   547         if(canGoLeft)
       
   548             {
       
   549             if(leftIdx > MinIdx)
       
   550                 --leftIdx;
       
   551             else        
       
   552                 canGoLeft = EFalse;
       
   553             }
       
   554 
       
   555         if(!canGoRight && !canGoLeft)
       
   556             return EFalse;  //-- no free entries in this sector
       
   557 
       
   558         if(canGoRight && ReadEntryL(rightIdx) == KSpareCluster)
       
   559             {
       
   560             aFatEntryIndex = rightIdx;
       
   561             return ETrue;
       
   562             }
       
   563 
       
   564         if (canGoLeft && ReadEntryL(leftIdx) == KSpareCluster)
       
   565             {
       
   566             aFatEntryIndex = leftIdx;
       
   567             return ETrue;
       
   568             }
       
   569         }//for(TUint i=0; i<numEntriesInSector; ++i)
       
   570 
       
   571     return EFalse;
       
   572     }
       
   573 
       
   574 
       
   575 
       
   576 //#################################################################################################################################
       
   577 //  CFat32LruCachePage implementation
       
   578 //#################################################################################################################################
       
   579 
       
   580 
       
   581 CFat32LruCachePage::CFat32LruCachePage(CFatPagedCacheBase& aCache)
       
   582                    :CFatCachePageBase(aCache)
       
   583     {
       
   584 
       
   585     ASSERT(IsPowerOf2(EntriesInPage()));
       
   586     }
       
   587 
       
   588 
       
   589 /**
       
   590     Factory function.
       
   591     @param aCache reference to the owning cache.
       
   592     @return pointer to the constructed object or NULL on error
       
   593 */
       
   594 CFat32LruCachePage* CFat32LruCachePage::NewL(CFatPagedCacheBase& aCache)
       
   595     {
       
   596 
       
   597     CFat32LruCachePage* pSelf = NULL;
       
   598     pSelf = new (ELeave) CFat32LruCachePage(aCache);
       
   599 
       
   600     CleanupStack::PushL(pSelf);
       
   601     
       
   602     pSelf->iData.CreateMaxL(pSelf->PageSize()); //-- allocate memory for the page
       
   603    
       
   604     CleanupStack::Pop();
       
   605 
       
   606     return pSelf;
       
   607     }
       
   608 
       
   609 
       
   610 //-----------------------------------------------------------------------------
       
   611 
       
   612 /**
       
   613     Get a pointer to the FAT32 entry in the page buffer.
       
   614     The page 's data shall be valid and the entry shall belong to this page.
       
   615     
       
   616     @param aFatIndex absolute FAT index (from the FAT start) of the entry
       
   617     @return pointer to the FAT32 entry in the page buffer.
       
   618 */
       
   619 TFat32Entry* CFat32LruCachePage::GetEntryPtr(TUint32 aFatIndex) const
       
   620     {
       
   621 
       
   622     ASSERT(IsValid() && IsEntryCached(aFatIndex));
       
   623     
       
   624     const TUint KEntryIndexInPage = aFatIndex & (EntriesInPage()-1); //-- number of entries in page is always a power of 2
       
   625 
       
   626     TFat32Entry* pEntry = ((TFat32Entry*)iData.Ptr()) + KEntryIndexInPage;
       
   627     return  pEntry;
       
   628     }
       
   629 
       
   630 //-----------------------------------------------------------------------------
       
   631 
       
   632 /**
       
   633     Read FAT32 entry from the cache.
       
   634     
       
   635     1. If the entry at aFatIndex doesn't belong to this page, returns EFalse
       
   636     2. If page's data are valid and the entry is cached just extracts data from the page buffer.
       
   637     3. If page's data are invalid but the entry's index belongs to this page, firstly reads data from the media and goto 2
       
   638     
       
   639     @param  aFatIndex entry's absolute FAT index (from the FAT start)
       
   640     @param  aResult on sucess there will be FAT32 entry value
       
   641     @return ETrue if the entry at aFatIndex belongs to this page (cached) and in this case aResult will contain this entry.
       
   642             EFalse if the entry isn't cached.
       
   643     
       
   644 */
       
   645 TBool CFat32LruCachePage::ReadCachedEntryL(TUint32 aFatIndex, TUint32& aResult) 
       
   646     {
       
   647     if(!IsEntryCached(aFatIndex))
       
   648         return EFalse;  //-- the page doesn't contain required index
       
   649     
       
   650     if(IsValid())
       
   651         {//-- read entry directly from page buffer, the cached data are valid
       
   652         aResult = (*GetEntryPtr(aFatIndex)) & KFat32EntryMask;
       
   653         }
       
   654     else
       
   655         {//-- aFatIndex belongs to this page, but the page is invalid and needs to be read from the media
       
   656         __PRINT1(_L("#-CFat32LruCachePage::ReadCachedEntry(%d) The page is invalid, reading from the media"), aFatIndex);
       
   657         aResult = ReadFromMediaL(aFatIndex);
       
   658         }
       
   659 
       
   660     return ETrue;
       
   661     }
       
   662 
       
   663 //-----------------------------------------------------------------------------
       
   664 
       
   665 /**
       
   666     Read the FAT32 cache page from the media and return required FAT32 entry.    
       
   667 
       
   668     @param  aFatIndex entry's absolute FAT index (from the FAT start)
       
   669     @return entry value at aFatIndex.
       
   670 */
       
   671 TUint32 CFat32LruCachePage::ReadFromMediaL(TUint32 aFatIndex)
       
   672     {
       
   673     //__PRINT1(_L("#-CFat32LruCachePage::ReadFromMediaL() FAT idx:%d"), aFatIndex);
       
   674 
       
   675     const TUint KFat32EntriesInPageLog2 = iCache.PageSizeLog2()-KFat32EntrySzLog2; //-- number of FAT32 entries in page is always a power of 2
       
   676 
       
   677     //-- find out index in FAT this page starts from
       
   678     iStartIndexInFAT = (aFatIndex >> KFat32EntriesInPageLog2) << KFat32EntriesInPageLog2;
       
   679 
       
   680     SetState(EInvalid); //-- mark the page as invalid just in case if the read fails.
       
   681     
       
   682     //-- read page from the media
       
   683     const TUint32 pageStartPos = iCache.FatStartPos() + (iStartIndexInFAT << KFat32EntrySzLog2);
       
   684     TInt nRes = iCache.ReadFatData(pageStartPos, iCache.PageSize(), iData);
       
   685     if(nRes != KErrNone)
       
   686         {
       
   687         __PRINT1(_L("#-CFat32LruCachePage::ReadFromMediaL() failed! code:%d"), nRes);
       
   688         User::Leave(nRes);
       
   689         }
       
   690 
       
   691     SetClean(); //-- mark this page as clean
       
   692 
       
   693     const TFat32Entry entry = (*GetEntryPtr(aFatIndex)) & KFat32EntryMask;
       
   694 
       
   695     return entry;
       
   696     }
       
   697 
       
   698 //-----------------------------------------------------------------------------
       
   699 
       
   700 /**
       
   701     Writes FAT cache page sector to the media (to all copies of the FAT)
       
   702     @param  aSector page sector number
       
   703 */
       
   704 void CFat32LruCachePage::DoWriteSectorL(TUint32 aSector)
       
   705     {
       
   706     //__PRINT1(_L("#-CFat32LruCachePage::DoWriteContiguousSectorsL() startSec:%d"),aSector);
       
   707 
       
   708     ASSERT(aSector < iCache.SectorsInPage());
       
   709 
       
   710     const TUint CacheSecSzLog2=iCache.SectorSizeLog2();
       
   711 
       
   712     TInt offset = 0;
       
   713     if(iStartIndexInFAT == 0 && aSector == 0)
       
   714         {//-- this is the very beginning of FAT32. We must skip FAT[0] & FAT[1] entries and do not write them to media.    
       
   715         offset = KFatFirstSearchCluster << KFat32EntrySzLog2; 
       
   716         }    
       
   717     
       
   718     const TUint8* pData = iData.Ptr()+offset+(aSector << CacheSecSzLog2);
       
   719     
       
   720     TUint32 dataLen = (1 << CacheSecSzLog2) - offset;
       
   721 
       
   722     const TUint32 mediaPosStart = iCache.FatStartPos() + (iStartIndexInFAT << KFat32EntrySzLog2) + (aSector << CacheSecSzLog2) + offset; 
       
   723     const TUint32 mediaPosEnd = mediaPosStart + dataLen; 
       
   724 
       
   725     //-- check if we are going to write beyond FAT. It can happen if the write granularity is bigger that the sector size.
       
   726     const TUint32 posFatEnd = iCache.FatStartPos() + iCache.FatSize();
       
   727     if(mediaPosEnd > posFatEnd)
       
   728         {//-- correct the leength of the data to write.
       
   729         dataLen -= (mediaPosEnd-posFatEnd);
       
   730         }
       
   731 
       
   732     TPtrC8 ptrData(pData, dataLen); //-- source data descriptor 
       
   733 
       
   734     TInt nRes = iCache.WriteFatData(mediaPosStart, ptrData);
       
   735     
       
   736     if(nRes != KErrNone)
       
   737         {
       
   738         __PRINT1(_L("#-CFat32LruCachePage::DoWriteSectorsL() failed! code:%d"), nRes);
       
   739         User::Leave(nRes);
       
   740         }
       
   741 
       
   742     
       
   743     //-- if we have FAT bit supercache and it is in consistent state, check if the entry in this cache differs from the data in dirty FAT cache sector. 
       
   744     CFatBitCache *pFatBitCache = iCache.BitCacheInterface();
       
   745     if(pFatBitCache && pFatBitCache->UsableState())
       
   746         {
       
   747         //-- absolute FAT cache sector number corresponding aSector number in _this_ cache page
       
   748         const TUint32 absSectorNum = (iStartIndexInFAT >> (CacheSecSzLog2-KFat32EntrySzLog2)) + aSector; 
       
   749 
       
   750         if(pFatBitCache->FatSectorHasFreeEntry(absSectorNum))
       
   751             {   //-- it means that the corresponding FAT cache sector may or may not contain free FAT entry.
       
   752             //-- in this case we need to repopulate corresponding bit cache entry. 
       
   753 
       
   754             const TUint32 numEntries = dataLen >> KFat32EntrySzLog2; //-- amount of FAT entries in this sector
       
   755             const TFat32Entry*  pFat32Entry = (const TFat32Entry* )pData;
       
   756     
       
   757             TBool bHasFreeFatEntry = EFalse;
       
   758 
       
   759             for(TUint i=0; i<numEntries; ++i)
       
   760                 {//-- look for free entries in this particular FAT cache sector.
       
   761                 if(pFat32Entry[i] == KSpareCluster)
       
   762                     {
       
   763                     bHasFreeFatEntry = ETrue;
       
   764                     break;
       
   765                     }
       
   766                 }
       
   767         
       
   768             if(!bHasFreeFatEntry)
       
   769                 {   //-- FAT bit cache indicates that FAT sector absSectorNum has free entries, but it doesn't.
       
   770                 //-- this is because we can only set "has free entry" flag in CAtaFatTable::WriteL().
       
   771                 //-- correct FAT bit cache entry 
       
   772                 pFatBitCache->SetFreeEntryInFatSector(absSectorNum, EFalse);
       
   773 
       
   774                 //__PRINT2(_L("#++ :DoWriteSectorL() Fixed FAT bit cache BitVec[%d]=%d"), absSectorNum, pFatBitCache->FatSectorHasFreeEntry(absSectorNum));
       
   775                 }
       
   776 
       
   777             }
       
   778         else //if(pBitCache->FatSectorHasFreeEntry(absSectorNum))
       
   779             {//-- don't need to do anything. The corresponding FAT cache sector never contained free FAT entry and
       
   780              //-- free FAT entry has never been written there in CAtaFatTable::WriteL().
       
   781             }
       
   782 
       
   783         }//if(pFatBitCache && pFatBitCache->UsableState())
       
   784  
       
   785 
       
   786     }
       
   787 
       
   788 
       
   789 //-----------------------------------------------------------------------------
       
   790 /**
       
   791     Write FAT32 entry at aFatIndex to the cache. Note that the data are not written to the media, only to the cache page.
       
   792     Corresponding page sector is marked as dirty and will be flushed on FlushL() call later.
       
   793 
       
   794     1. If the entry at aFatIndex doesn't belong to this page, returns EFalse
       
   795     2. If page's data are valid and the entry is cached, copies data to the page buffer and marks sector as dirty.
       
   796     3. If page's data are invalid but the entry's index belongs to this page, firstly reads data from the media and goto 2
       
   797 
       
   798     @param  aFatIndex entry's absolute FAT index (from the FAT start)
       
   799     @param  aFatEntry FAT32 entry value
       
   800     @return ETrue if the entry at aFatIndex belongs to this page (cached) and in this case aResult will contain this entry.
       
   801             EFalse if the entry isn't cached.
       
   802 
       
   803 */
       
   804 TBool CFat32LruCachePage::WriteCachedEntryL(TUint32 aFatIndex, TUint32 aFatEntry)
       
   805     {
       
   806 
       
   807     if(!IsEntryCached(aFatIndex)) 
       
   808         return EFalse;  //-- the page doesn't contain required index
       
   809     
       
   810     if(!IsValid())
       
   811         {//-- we are trying to write data to the page that has invalid data. //-- read the data from the media first.
       
   812         ReadFromMediaL(aFatIndex);
       
   813         }
       
   814     
       
   815     //-- for FAT32 only low 28 bits are used, 4 high are reserved; preserve them
       
   816     TFat32Entry* pEntry = GetEntryPtr(aFatIndex);
       
   817     const TFat32Entry orgEntry = *pEntry;
       
   818     *pEntry = (orgEntry & ~KFat32EntryMask) | (aFatEntry & KFat32EntryMask);
       
   819 
       
   820     //-- mark corresponding sector of the cache page as dirty
       
   821     const TUint entryIndexInPage = aFatIndex & (EntriesInPage()-1); //-- number of entries in page is always a power of 2
       
   822     const TUint dirtySectorNum   = entryIndexInPage >> (iCache.SectorSizeLog2() - KFat32EntrySzLog2);
       
   823 
       
   824     ASSERT(dirtySectorNum < iCache.SectorsInPage());
       
   825 
       
   826     iDirtySectors.SetBit(dirtySectorNum);
       
   827     SetState(EDirty); //-- mark page as dirty.
       
   828 
       
   829     return ETrue;
       
   830     }
       
   831 
       
   832 
       
   833 
       
   834 //#################################################################################################################################
       
   835 //  CFatBitCache implementation
       
   836 //#################################################################################################################################
       
   837 
       
   838 //-- define this macro for extra debugging facilities for the CFatBitCache
       
   839 //-- probably needs to be removed completely as soon as everything settles
       
   840 //#define FAT_BIT_CACHE_DEBUG
       
   841 
       
   842 //----------------------------------------------------------------------------- 
       
   843 
       
   844 CFatBitCache::CFatBitCache(CFat32LruCache& aOnwerFatCache)
       
   845              :iOwnerFatCache(aOnwerFatCache)
       
   846     {
       
   847     SetState(EInvalid);
       
   848     DBG_STATEMENT(iPopulatingThreadId=0);
       
   849     }
       
   850 
       
   851 CFatBitCache::~CFatBitCache()
       
   852     {
       
   853     Close();
       
   854     }
       
   855 
       
   856 //----------------------------------------------------------------------------- 
       
   857 /**
       
   858     FAT bit supercache factory method
       
   859     @return pointer to the created object or NULL if it coud not create or initialise it.
       
   860 */
       
   861 CFatBitCache* CFatBitCache::New(CFat32LruCache& aOnwerFatCache)
       
   862     {
       
   863     __PRINT(_L("#++ CFatBitCache::New()"));
       
   864     
       
   865     CFatBitCache* pSelf = NULL;
       
   866     pSelf = new CFatBitCache(aOnwerFatCache);
       
   867 
       
   868     if(!pSelf)
       
   869         return NULL; //-- failed to create object
       
   870 
       
   871     TInt nRes = pSelf->Initialise();
       
   872     if(nRes != KErrNone)
       
   873         {//-- failed to initialise the object
       
   874         delete pSelf;
       
   875         pSelf = NULL;
       
   876         }
       
   877 
       
   878     return pSelf;
       
   879     }
       
   880 
       
   881 
       
   882 //-----------------------------------------------------------------------------
       
   883 
       
   884 /** 
       
   885     Initialisation.
       
   886     Note that this cache suports FAT32 only.
       
   887     @return KErrNone on success; otherwise standard error code.
       
   888 */
       
   889 TInt CFatBitCache::Initialise()
       
   890     {
       
   891     __PRINT(_L("#++ CFatBitCache::Initialise()"));
       
   892     
       
   893     Close();
       
   894     
       
   895     //-- only FAT32 supported
       
   896     if(iOwnerFatCache.FatType() != EFat32)
       
   897         {
       
   898         ASSERT(0);
       
   899         Fault(EFatCache_BadFatType);
       
   900         }
       
   901 
       
   902     //-- create the bit vector. each bit position there represents one FAT cache sector (in FAT cache page terms, see FAT page structure)
       
   903     const TUint fatSize = iOwnerFatCache.FatSize(); //-- FAT size in bytes
       
   904     const TUint fatCacheSecSize = Pow2(iOwnerFatCache.SectorSizeLog2()); //-- FAT cache sector size
       
   905     const TUint maxFatUsableCacheSectors = (fatSize + (fatCacheSecSize-1)) >> iOwnerFatCache.SectorSizeLog2(); //-- maximal number of usable fat cache sectors in whole FAT table
       
   906 
       
   907     //-- create a bit vector
       
   908     __PRINT1(_L("#++ CFatBitCache::Initialise() FAT supercache bits:%u"), maxFatUsableCacheSectors);
       
   909     
       
   910     TInt nRes = iBitCache.Create(maxFatUsableCacheSectors);
       
   911     if(nRes != KErrNone)
       
   912         {
       
   913         __PRINT1(_L("#++ Failed to create a bit vector! code:%d"), nRes);
       
   914         return nRes;
       
   915         }
       
   916     
       
   917     //-- calculate the coefficient to be used to convet FAT index to FAT cache sector number (bit vector index).
       
   918     iFatIdxToSecCoeff = iOwnerFatCache.SectorSizeLog2()-KFat32EntrySzLog2;
       
   919     SetState(ENotPopulated);
       
   920 
       
   921     return KErrNone;    
       
   922     }
       
   923 
       
   924 //-----------------------------------------------------------------------------
       
   925 /**
       
   926     Closes the cache and deallocates bit vector memory.
       
   927 */
       
   928 void CFatBitCache::Close()
       
   929     {
       
   930     __PRINT(_L("#++ CFatBitCache::Close()"));
       
   931     
       
   932     //-- this method must not be called during populating (optionally by another thread)
       
   933     ASSERT(State() != EPopulating);
       
   934     ASSERT(iPopulatingThreadId == 0);
       
   935 
       
   936     iBitCache.Close();
       
   937     SetState(EInvalid);
       
   938     }
       
   939 
       
   940 //-----------------------------------------------------------------------------
       
   941 
       
   942 /**
       
   943     Tell the cache that we are starting to populate it. 
       
   944     N.B. Start, Finish and populating methods shall be called from the same thread. 
       
   945     Only one thread can be populating the bit vector; 
       
   946 
       
   947     @return ETrue on success. Efalse means that the cache is in the invalid state for some reason.
       
   948 */
       
   949 TBool CFatBitCache::StartPopulating()
       
   950     {
       
   951     __PRINT2(_L("#++ CFatBitCache::StartPopulating(), State:%d, ThreadId:%d"), State(), (TUint)RThread().Id());
       
   952 
       
   953     if(State() != ENotPopulated)
       
   954         {//-- wrong state
       
   955         ASSERT(0);
       
   956         return EFalse; 
       
   957         }
       
   958     
       
   959     ASSERT(iPopulatingThreadId == 0);
       
   960 
       
   961     iBitCache.Fill(0);
       
   962     SetState(EPopulating);
       
   963     
       
   964     //-- store the the ID of the thread that starts populating the cache; it'll be checked later during populating.
       
   965     DBG_STATEMENT(iPopulatingThreadId = RThread().Id());
       
   966 
       
   967     return ETrue;
       
   968     }
       
   969 
       
   970 //-----------------------------------------------------------------------------
       
   971 
       
   972 /**
       
   973     Tell the cache that we have finished to populate it. 
       
   974 
       
   975     @return ETrue on success. EFalse means that the cache is in the invalid state for some reason.
       
   976 */
       
   977 TBool CFatBitCache::FinishPopulating(TBool aSuccess)
       
   978     {
       
   979     __PRINT2(_L("#++ CFatBitCache::PopulatingFinished(), ThreadId:%d, success:%d"), (TUint)RThread().Id(), aSuccess);
       
   980 
       
   981     if(State() != EPopulating)
       
   982         {//-- wrong state
       
   983         ASSERT(0);
       
   984         return EFalse; 
       
   985         }
       
   986 
       
   987     ASSERT(iPopulatingThreadId == RThread().Id()); //-- check that this method is called from the same thread that started populating
       
   988     DBG_STATEMENT(iPopulatingThreadId = 0); 
       
   989     
       
   990     if(aSuccess)
       
   991         SetState(EPopulated); //-- the cache is usable; populated OK
       
   992     else
       
   993         SetState(EInvalid);   //-- the cache isn't populated properly, make it not usable
       
   994 
       
   995     return ETrue;
       
   996     }
       
   997 
       
   998 //-----------------------------------------------------------------------------
       
   999 /**
       
  1000     Tell FAT bit cache that there is a free entry at FAT aFatIndex.
       
  1001     Only this method can be used to populate the bit array (in EPopulating state). 
       
  1002     Other methods can't access bit array in EPopulating state i.e. it is safe to populate the cache
       
  1003     from the thread other than FS drive thread (e.g within background FAT scan)
       
  1004 
       
  1005     @param  aFatIndex free FAT32 entry index
       
  1006     @return ETrue on success. EFalse means that the cache is in the invalid state for some reason.
       
  1007 */
       
  1008 TBool CFatBitCache::SetFreeFatEntry(TUint32 aFatIndex)
       
  1009     {
       
  1010     //__PRINT3(_L("#++  ReportFreeFatEntry: idx:%d, state:%s, tid:%d"), aFatIndex, State(), (TUint)RThread().Id());
       
  1011 
       
  1012     if(State() != EPopulating && State() != EPopulated)
       
  1013         {//-- wrong state, this can happen if someone forcedly invalidated this cache during populating
       
  1014         return EFalse; 
       
  1015         }
       
  1016 
       
  1017 #if defined _DEBUG && defined FAT_BIT_CACHE_DEBUG 
       
  1018     //-- This leads to serious performance degradation, so be careful with it.
       
  1019     if(State() == EPopulating)
       
  1020         {//-- check that this method is called from the same thread that started populating
       
  1021         if(iPopulatingThreadId != RThread().Id())
       
  1022             {
       
  1023             __PRINT3(_L("#++ !! ReportFreeFatEntry: Access from different thread!! idx:%d, state:%d, tid:%d"), aFatIndex, State(), (TUint)RThread().Id());
       
  1024             }
       
  1025         //ASSERT(iPopulatingThreadId == RThread().Id()); 
       
  1026         }
       
  1027 #endif
       
  1028     
       
  1029     //-- set bit to '1' which indicates that the FAT cache sector corresponding to the aFatIndex has at least one free FAT entry
       
  1030     const TUint32 bitNumber = FatIndexToCacheSectorNumber(aFatIndex); //-- index in the bit array corresponding FAT cache sector
       
  1031 
       
  1032 #if defined _DEBUG && defined FAT_BIT_CACHE_DEBUG 
       
  1033     //-- This leads to serious performance degradation, so be careful with it.
       
  1034     TBool b = iBitCache[bitNumber];
       
  1035     if(!b && State()==EPopulated)
       
  1036         {//-- someone is reporting a free entry in the given cache sector.
       
  1037         __PRINT1(_L("#++ CFatBitCache::ReportFreeFatEntry BitVec[%d]=1"), bitNumber);
       
  1038         }
       
  1039 #endif
       
  1040 
       
  1041 
       
  1042     iBitCache.SetBit(bitNumber);
       
  1043     
       
  1044     return ETrue;
       
  1045     }
       
  1046 
       
  1047 //-----------------------------------------------------------------------------
       
  1048 /**
       
  1049     Forcedly mark a part of the FAT bit super cache as containing free clusters (or not).
       
  1050  
       
  1051     @param  aStartFatIndex  start FAT index of the range
       
  1052     @param  aEndFatIndex    end FAT index of the range
       
  1053     @param  aAsFree         if ETrue, the range will be marked as containing free clusters
       
  1054 */
       
  1055 void CFatBitCache::MarkFatRange(TUint32 aStartFatIndex, TUint32 aEndFatIndex, TBool aAsFree)
       
  1056     {
       
  1057     __PRINT3(_L("#++ CFatBitCache::MarkFatRange(%d, %d, %d)"), aStartFatIndex, aEndFatIndex, aAsFree);
       
  1058 
       
  1059     ASSERT(State() == EPopulating || State() == EPopulated);
       
  1060 
       
  1061     const TUint32 bitNumberStart = FatIndexToCacheSectorNumber(aStartFatIndex);
       
  1062     const TUint32 bitNumberEnd   = FatIndexToCacheSectorNumber(aEndFatIndex);
       
  1063 
       
  1064     iBitCache.Fill(bitNumberStart, bitNumberEnd, aAsFree);
       
  1065     }
       
  1066 
       
  1067 
       
  1068 //-----------------------------------------------------------------------------
       
  1069 /**
       
  1070     Try to locate closest to the aFatIndex free FAT entry in the FAT32 LRU cache.
       
  1071     This is done by several steps:
       
  1072 
       
  1073     1. Try to find FAT cache sector containing free FAT entry (by using FAT sectors bitmap)
       
  1074     2. locate free FAT entry within this sector.
       
  1075     
       
  1076     @param      aFatIndex  in: absolute FAT entry index that will be used to start search from (we need to find the closest free entry to it)
       
  1077                            out: may contain FAT index of the located free entry.
       
  1078                             
       
  1079     @return     one of the completion codes: 
       
  1080                 KErrNone      free entry found and its index is in aFatIndex  
       
  1081                 KErrNotFound  FAT sector closest to the aFatIndex entry doesn't contain free FAT entries; the conflict is resolved, need to call this method again
       
  1082                 KErrEof       couldn't find any free sectors in FAT; need to fall back to the old search method
       
  1083                 KErrCorrupt   if the state of the cache is inconsistent
       
  1084 */
       
  1085 TInt CFatBitCache::FindClosestFreeFatEntry(TUint32& aFatIndex)
       
  1086     {
       
  1087     const TUint32 startFatCacheSec = FatIndexToCacheSectorNumber(aFatIndex);
       
  1088     
       
  1089     //__PRINT2(_L("#++ CFatBitCache::FindClosestFreeFatEntry() start idx:%d, start cache sec:%d"), aFatIndex, startFatCacheSec);
       
  1090 
       
  1091     ASSERT(aFatIndex >= KFatFirstSearchCluster);
       
  1092     if(!UsableState())
       
  1093         {
       
  1094         ASSERT(0);
       
  1095         return KErrCorrupt;
       
  1096         }
       
  1097 
       
  1098     TUint32 fatSeekCacheSec = startFatCacheSec; //-- FAT cache sector number that has free FAT entry, used for search . 
       
  1099     TUint32 fatSeekIndex = aFatIndex;           //-- FAT index to start search with
       
  1100 
       
  1101     //-- 1. look if FAT sector that corresponds to the aStartFatIndex already has free entries.
       
  1102     //-- 2. if not, try to locate closest FAT cache sector that has by searching a bit vector
       
  1103     if(FatSectorHasFreeEntry(fatSeekCacheSec))
       
  1104         {
       
  1105         }
       
  1106     else
       
  1107         {//-- look in iBitCache for '1' entries nearest to the fatCacheSec, right side priority 
       
  1108 
       
  1109         if(!iBitCache.Find(fatSeekCacheSec, 1, RBitVector::ENearestR))
       
  1110             {//-- strange situation, there are no '1' bits in whole vector, search failed
       
  1111             __PRINT(_L("#++ CFatBitCache::FindClosestFreeFatEntry() bit vector search failed!"));
       
  1112             return KErrEof;
       
  1113             }
       
  1114     
       
  1115         //-- bit cache found FAT sector(fatSeekCacheSec) that may have free FAT entries
       
  1116         //-- calculate FAT entry start index in this sector
       
  1117         fatSeekIndex = Max(KFatFirstSearchCluster, CacheSectorNumberToFatIndex(fatSeekCacheSec));
       
  1118         }
       
  1119 
       
  1120     //-- here we have absolute FAT cache sector number, which may contain at least one free FAT entty
       
  1121     ASSERT(FatSectorHasFreeEntry(fatSeekCacheSec));
       
  1122 
       
  1123     //-- ask FAT cache to find the exact index of free FAT entry in this particular FAT cache sector
       
  1124     TInt  nRes;
       
  1125     TBool bFreeEntryFound=EFalse;
       
  1126 
       
  1127     TRAP(nRes, bFreeEntryFound = iOwnerFatCache.FindFreeEntryInCacheSectorL(fatSeekIndex));
       
  1128     if(nRes != KErrNone)
       
  1129         {//-- it's possible on media read error
       
  1130         return KErrCorrupt;
       
  1131         }
       
  1132 
       
  1133     if(bFreeEntryFound)
       
  1134         {//-- found free entry at aNewFreeEntryIndex
       
  1135         aFatIndex = fatSeekIndex;
       
  1136         return KErrNone;   
       
  1137         }
       
  1138 
       
  1139     //-- bit cache mismatch; its entry ('1') indicates that cache sector number fatCacheSec has free FAT entries,
       
  1140     //-- while in reality it doesnt. We need to fix the bit cache.
       
  1141     //__PRINT1(_L("#++ CFatBitCache::FindClosestFreeFatEntry  fixing cache conflict; BitVec[%d]=0"), fatSeekCacheSec);
       
  1142     SetFreeEntryInFatSector(fatSeekCacheSec, EFalse);
       
  1143 
       
  1144     return KErrNotFound;
       
  1145     }
       
  1146 
       
  1147 
       
  1148 //-----------------------------------------------------------------------------
       
  1149 /**
       
  1150     Print out the contents of the object. This is a debug only method
       
  1151 */
       
  1152 void CFatBitCache::Dump() const
       
  1153 {
       
  1154 #if defined _DEBUG && defined FAT_BIT_CACHE_DEBUG 
       
  1155 
       
  1156     const TUint32 vecSz = iBitCache.Size();
       
  1157     __PRINT2(_L("#++ CFatBitCache::Dump(): state:%d, entries:%d"), State(), vecSz);
       
  1158 
       
  1159 
       
  1160     TBuf<120> printBuf;
       
  1161     const TUint KPrintEntries = 32;
       
  1162     
       
  1163     TUint i;
       
  1164     printBuf.Append(_L("    "));
       
  1165     for(i=0; i<KPrintEntries; ++i)
       
  1166     {
       
  1167         printBuf.AppendFormat(_L("%02d "),i);
       
  1168     }
       
  1169     
       
  1170     __PRINT(printBuf);
       
  1171     for(i=0; i<vecSz;)
       
  1172     {
       
  1173         printBuf.Format(_L("%03d: "), i);
       
  1174         for(TInt j=0; j<KPrintEntries; ++j)
       
  1175         {
       
  1176             if(i >= vecSz)
       
  1177                 break;
       
  1178 
       
  1179             printBuf.AppendFormat(_L("% d  "), (iBitCache[i]!=0));
       
  1180             ++i;
       
  1181         }    
       
  1182         __PRINT(printBuf);
       
  1183         
       
  1184     }
       
  1185 #endif
       
  1186 }
       
  1187 
       
  1188 
       
  1189 
       
  1190 
       
  1191 
       
  1192 
       
  1193 
       
  1194 
       
  1195 
       
  1196 
       
  1197 
       
  1198 
       
  1199 
       
  1200 
       
  1201 
       
  1202 
       
  1203 
       
  1204 
       
  1205 
       
  1206 
       
  1207 
       
  1208 
       
  1209 
       
  1210 
       
  1211 
       
  1212 
       
  1213 
       
  1214 
       
  1215 
       
  1216 
       
  1217 
       
  1218 
       
  1219 
       
  1220 
       
  1221 
       
  1222 
       
  1223 
       
  1224 
       
  1225 
       
  1226 
       
  1227