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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // f32\sfat\sl_cache.cpp
21 //---------------------------------------------------------------------------------------------------------------------------------
24 CWTCachePage factory function.
25 @param aPageSizeLog2 Log2(cache page size in bytes)
26 @return a pointer to the created object.
28 CWTCachePage* CWTCachePage::NewL(TUint32 aPageSizeLog2)
30 CWTCachePage* pSelf = new (ELeave)CWTCachePage;
31 pSelf->ConstructL(aPageSizeLog2);
37 2nd stage constructor.
38 @param aPageSizeLog2 Log2(cache page size in bytes)
40 void CWTCachePage::ConstructL(TUint32 aPageSizeLog2)
42 iData.CreateMaxL(1 << aPageSizeLog2);
45 CWTCachePage::CWTCachePage()
47 iStartPos = 0xDeadDeadul;
51 CWTCachePage::~CWTCachePage()
58 //---------------------------------------------------------------------------------------------------------------------------------
60 CMediaWTCache::CMediaWTCache(TDriveInterface& aDrive)
61 :iDrive(aDrive), iPageSizeLog2(0), iAllPagesValid(EFalse)
63 iCacheDisabled = EFalse;
67 CMediaWTCache::~CMediaWTCache()
70 TInt cnt = iPages.Count();
81 Directory cache factory function.
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
87 @return a pointer to the created object.
89 CMediaWTCache* CMediaWTCache::NewL(TDriveInterface& aDrive, TUint32 aNumPages, TUint32 aPageSizeLog2)
91 #ifndef ENABLE_DEDICATED_DIR_CACHE
92 //-- dedicated directory cache isn't enabled
93 (void)aDrive; //-- supress compiler's warning
94 (void)aClusterSizeLog2;
98 //-- dedicated directory cache is enabled, create it
99 ASSERT(aPageSizeLog2);
102 CMediaWTCache* pSelf = new (ELeave) CMediaWTCache(aDrive);
104 CleanupStack::PushL(pSelf);
105 pSelf->ConstructL(aNumPages, aPageSizeLog2);
114 2nd stage constructor.
115 @param aNumPages number of pages in the directory cache.
116 @param aPageSizeLog2 Log2(single cache page size in bytes)
118 void CMediaWTCache::ConstructL(TUint32 aNumPages, TUint32 aPageSizeLog2)
120 ASSERT(aNumPages && aPageSizeLog2);
122 __PRINT2(_L("#CMediaWTCache::CreateL() Pages=%d, PageSize=%d"), aNumPages, 1<<aPageSizeLog2);
124 iPageSizeLog2 = aPageSizeLog2;
126 //-- create cache pages
127 for(TUint cnt=0; cnt<aNumPages; ++cnt)
129 CWTCachePage* pPage = CWTCachePage::NewL(aPageSizeLog2);
130 iPages.Append(pPage);
138 @return size of the cache in bytes. Can be 0.
140 TUint32 CMediaWTCache::CacheSizeInBytes() const
142 const TUint32 cacheSz = iPages.Count() << iPageSizeLog2; //-- Page size is always power of 2
147 Implementation of pure virtual function.
148 @see MWTCacheInterface::MakePageMRU()
150 void CMediaWTCache::MakePageMRU(TInt64 /*aPos*/)
156 Implementation of pure virtual function.
157 @see MWTCacheInterface::PageSizeInBytesLog2()
159 TUint32 CMediaWTCache::PageSizeInBytesLog2() const
161 return iPageSizeLog2;
167 @param aFunction control function
168 @param aParam1 just arbitrary parameter
169 @param aParam2 just arbitrary parameter
170 @return Standard error code.
173 TInt CMediaWTCache::Control(TUint32 aFunction, TUint32 aParam1, TAny* /*aParam2*/)
175 TInt nRes = KErrNotSupported;
180 //-- disable / enable cache, for debug
181 //-- if aParam1 !=0 cache will be disabled, enabled otherwise
183 iCacheDisabled = aParam1 ? 1 : 0;
194 __PRINT1(_L("CMediaWTCache::Control() invalid function: %d"), aFunction);
199 (void)aFunction; //-- supress warnings
201 User::Invariant(); //-- don't call this method in release build
207 //-------------------------------------------------------------------------------------
209 Invalidate whole cache
211 void CMediaWTCache::InvalidateCache(void)
213 const TUint nPages = iPages.Count();
214 for(TUint i=0; i<nPages; ++i)
216 iPages[i]->iValid=EFalse;
219 iAllPagesValid = EFalse;
222 //-------------------------------------------------------------------------------------
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.
229 @param aPos media position. If it is cached, the corresponding single cache page will be marked as invalid
231 void CMediaWTCache::InvalidateCachePage(TUint64 aPos)
233 const TUint nPages = iPages.Count();
234 for(TUint i=0; i<nPages; ++i)
236 if( iPages[i]->PosCached(aPos))
238 iPages[i]->iValid=EFalse;
239 iAllPagesValid = EFalse;
246 //-------------------------------------------------------------------------------------
249 Find cache page by given media position.
251 @param aPos linear media position
252 @return positive cache page number or -1 if no pages containing data at aPos found.
254 TInt CMediaWTCache::FindPageByPos(TInt64 aPos) const
256 const TUint nPages = iPages.Count();
257 for(TUint i=0; i<nPages; ++i)
259 if( iPages[i]->PosCached(aPos))
267 Push given page aPageNo to the 1st position in the pages array. Used for LRU mechanism
269 @param aPageNo page number to be made LRU
271 void CMediaWTCache::MakePageLRU(TInt aPageNo)
276 return; //-- nothing to do
278 const TInt nPages = iPages.Count();
279 ASSERT(aPageNo < nPages);
283 CWTCachePage* pPage=iPages[aPageNo];
285 iPages.Remove(aPageNo);
286 iPages.Insert(pPage,0); //-- insert the pointer to the 1st position in the array
287 ASSERT(nPages == iPages.Count());
292 Find a spare page or evict the last from LRU list
296 TUint32 CMediaWTCache::GrabPage() const
298 const TUint nPages = iPages.Count();
301 {//-- try to find unused cache page
302 for(TUint i=0; i<nPages; ++i)
304 if(! iPages[i]->iValid)
305 return i; //-- found unused page
309 //-- no spare pages, evict the last one, it shall be last used
310 iAllPagesValid = ETrue;
315 Find a spare page or evict the last from LRU list, then read data to this page from media starting from aPos
317 @param aPos media linear position from where the data will be read to the page
318 @return cache page number
320 TUint32 CMediaWTCache::GrabReadPageL(TInt64 aPos)
322 //-- find a spare or page to evict
323 TUint nPage = GrabPage();
324 CWTCachePage& page = *iPages[nPage];
326 //-- read data to this page
327 page.iStartPos = CalcPageStartPos(aPos);
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]);
331 const TInt nErr = iDrive.ReadNonCritical(page.iStartPos, PageSize(), page.iData);
333 {//-- some serious problem occured during reading, invalidate cache.
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.
347 @param aPos media linear position to find in the cache
348 @return cache page number
351 TUint32 CMediaWTCache::FindOrGrabReadPageL(TInt64 aPos)
353 //-- find out if aPos is in cache
354 TInt nPage=FindPageByPos(aPos);
357 {//-- no page contains data to read
358 nPage = GrabReadPageL(aPos); //-- find a spare page and read data into it
365 Finds out if the media position "aPosToSearch" is in the cache and returns cache page information in this case.
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
370 @return 0 if aPosToSearch isn't cached, otherwise cache page size in bytes (see also aCachedPosStart).
372 TUint32 CMediaWTCache::PosCached(const TInt64& aPosToSearch, TInt64& aCachedPosStart)
374 TInt nPage = FindPageByPos(aPosToSearch);
376 return 0; //-- cache page containing aPos not found
378 aCachedPosStart = iPages[nPage]->iStartPos;
384 Read data from the media through the directory cache.
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
390 void CMediaWTCache::ReadL(TInt64 aPos,TInt aLength,TDes8& aDes)
395 {//-- cache is disabled for debug purposes
396 User::LeaveIfError(iDrive.ReadNonCritical(aPos, aLength, aDes));
401 const TUint32 PageSz = PageSize();//-- cache page size
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];
407 const TUint32 bytesToPageEnd = (TUint32)(pPage->iStartPos+PageSz - aPos); //-- number of bytes from aPos to the end of the page
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);
415 {//-- Data to be read cross cache page boundary or probably we have more than 1 page to read
417 TUint32 dataLen(aLength); //-- current data length
418 TInt64 currMediaPos(aPos); //-- current media position
420 //-- 1. read data that are already in the current page
421 aDes.Copy(pPage->PtrInCachePage(currMediaPos), bytesToPageEnd);
423 dataLen -= bytesToPageEnd;
424 currMediaPos += bytesToPageEnd;
426 //-- 2. read whole pages of data
427 while(dataLen >= PageSz)
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];
432 aDes.Append(pPage->PtrInCachePage(currMediaPos),PageSz);
435 currMediaPos += PageSz;
437 MakePageLRU(nPage); //-- push the page to the top of the priority list
440 //-- 3. read the rest of the data
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];
446 aDes.Append(pPage->PtrInCachePage(currMediaPos), dataLen);
449 } //else((TUint32)aLength <= bytesToPageEnd)
452 MakePageLRU(nPage); //-- push the page to the top of the priority list
457 Write data to the media through the directory cache.
459 @param aPos linear media position to start writing with
460 @param aDes data to write
462 void CMediaWTCache::WriteL(TInt64 aPos,const TDesC8& aDes)
467 {//-- cache is disabled for debug purposes
468 User::LeaveIfError(iDrive.WriteCritical(aPos,aDes));
473 TUint32 dataLen = aDes.Size();
474 const TUint8* pData = aDes.Ptr();
475 const TUint32 PageSz = PageSize(); //-- cache page size
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];
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
488 {//-- Data to be written cross cache page boundary or probably we have more than 1 page to write
490 TInt64 currMediaPos(aPos); //-- current media position
492 //-- 1. update the current page
493 Mem::Copy(pPage->PtrInCachePage(currMediaPos), pData, bytesToPageEnd);
495 pData += bytesToPageEnd;
496 currMediaPos += bytesToPageEnd;
497 dataLen -= bytesToPageEnd;
499 //-- 2. write whole pages of data to the cache
500 while(dataLen >= PageSz)
502 nPage = FindPageByPos(currMediaPos); //-- ?? shall we read data there ??
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
513 currMediaPos += PageSz;
517 //-- 3. write the rest of the data
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];
523 Mem::Copy(pPage->PtrInCachePage(currMediaPos), pData, dataLen);
526 }// else(dataLen <= bytesToPageEnd)
529 //-- write data to the media
530 const TInt nErr = iDrive.WriteCritical(aPos,aDes);
532 {//-- some serious problem occured during writing, invalidate cache.
537 MakePageLRU(nPage); //-- push the page to the top of the priority list