Update contrib.
1 // Copyright (c) 2008-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_dir_cache.cpp
18 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
19 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
21 //!! WARNING!! DO NOT edit this file !! '\sfat' component is obsolete and is not being used. '\sfat32'replaces it
23 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
24 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
28 #include "sl_dir_cache.h"
30 //======================================================================
31 TDynamicDirCachePage::~TDynamicDirCachePage()
36 The static cache page creation function.
37 Cache page objects are not supposed to be created on the stack, so this factory function is required.
39 TDynamicDirCachePage* TDynamicDirCachePage::NewL(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
41 return new(ELeave) TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr);
45 Cache page constructor.
46 @param aOwnerCache pointer of the cache that owns this page
47 @param aStartMedPos the start address on the media that this page caches
48 @param aStartRamAddr the start address in the ram that this page content lives
50 TDynamicDirCachePage::TDynamicDirCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
51 :iStartMedPos(aStartMedPos),
52 iStartRamAddr(aStartRamAddr),
53 iOwnerCache(aOwnerCache),
57 // __PRINT3(_L("TDynamicDirCachePage::TDynamicDirCachePage(aStartMedPos=%lx, aStartRamAddr=0x%X, aPageSize=%u)"), aStartMedPos, aStartRamAddr, PageSizeInBytes());
61 /////////////////////////////// class CDynamicDirCache::TLookupEntry ///////////////////////////
63 Required by RHashSet<TLookupEntry> to identify individual hash set entries.
66 TBool IdentityFunction(const TLookupEntry& aEntry1, const TLookupEntry& aEntry2)
68 // only check starting med pos for hash searching
69 return aEntry1.iPos == aEntry2.iPos;
72 Required by RHashSet<TLookupEntry> to generate hash value.
75 TUint32 HashFunction(const TLookupEntry& aEntry)
77 return (DefaultHash::Integer(I64HIGH(aEntry.iPos)) + DefaultHash::Integer(I64LOW(aEntry.iPos)));
80 /////////////////////////////// class CDynamicDirCache ///////////////////////////
81 CDynamicDirCache::~CDynamicDirCache()
83 // __PRINT(_L("CDynamicDirCache::~CDynamicDirCache()"));
85 // we should never decommit locked pages
86 while (!iLockedQ.IsEmpty())
88 TDynamicDirCachePage* page = iLockedQ.Last();
89 DeQueue(page); // remove from queue
90 LookupTblRemove(page->StartPos()); // remove from lookuptable
93 ASSERT(iLockedQCount == 0);
95 while (!iUnlockedQ.IsEmpty())
97 TDynamicDirCachePage* page = iUnlockedQ.Last();
98 DeQueue(page); // remove from queue
99 LookupTblRemove(page->StartPos()); // remove from lookuptable
100 DecommitPage(page); // inform cache client to decommit page memory
103 ASSERT(iUnlockedQCount == 0);
107 ASSERT(iLookupTable.Count() == 0);
108 iLookupTable.Close();
109 if (iCacheMemoryClient)
110 iCacheMemoryClient->Reset();
114 Constructor of CDynamicDirCache.
115 @param aDrive local drive interface to read/write media
116 @param aMinPageNum the minimum page number for the cache, includes iActive page and locked pages.
117 @param aMaxPageNum the maximum page number for the cache, includes iActive page, locked pages and unlocked pages.
118 @param aPageSizeInBytesLog2 the log2 value of page size in bytes, assumes page size is always a power of two
120 CDynamicDirCache::CDynamicDirCache(TFatDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeInBytesLog2)
121 :iPageSizeLog2(aPageSizeInBytesLog2),
122 iMinSizeInPages(aMinPageNum),
123 iMaxSizeInPages(aMaxPageNum),
125 iLockedQ(_FOFF(TDynamicDirCachePage, iLink)),
126 iUnlockedQ(_FOFF(TDynamicDirCachePage, iLink)),
129 iHashFunction(HashFunction),
130 iIdentityFunction(IdentityFunction),
131 iLookupTable(iHashFunction, iIdentityFunction)
133 iPageSizeInBytes = 1 << aPageSizeInBytesLog2;
134 iCacheDisabled = EFalse;
135 iMinCacheSizeInBytes = aMinPageNum << aPageSizeInBytesLog2;
136 iMaxCacheSizeInBytes = aMaxPageNum << aPageSizeInBytesLog2;
137 ASSERT(iPageSizeInBytes && iPageSizeInBytes <= iMinCacheSizeInBytes && iMinCacheSizeInBytes <= iMaxCacheSizeInBytes);
138 // initial value, will be reset from outside
143 Second phase constructor of CDynamicDirCache.
144 @param aClientName the identification of cache memeory client this cache connects
146 void CDynamicDirCache::ConstructL(const TDesC& aClientName)
148 // __PRINT3(_L("CDynamicDirCache::ConstructL(Min=%u, Max=%u, page=%u)"), iMinCacheSizeInBytes, iMaxCacheSizeInBytes, iPageSizeInBytes);
149 CCacheMemoryManager* manager = CCacheMemoryManagerFactory::CacheMemoryManager();
152 // client will register itself onto cache memory manager when created
153 // note this operation may leave under OOM condition
154 iCacheMemoryClient = manager->ConnectClientL(aClientName, iMinSizeInPages * PageSizeInSegs(), iMaxSizeInPages * PageSizeInSegs());
158 User::Leave(KErrNotSupported);
161 ASSERT(iCacheMemoryClient);
162 if (!iCacheMemoryClient)
164 User::Leave(KErrNoMemory);
167 // reserve active page
168 iActivePage = AllocateAndLockNewPageL(0);
172 User::Leave(KErrNoMemory);
174 iActivePage->SetPageType(TDynamicDirCachePage::EActivePage);
178 Static factory function of CDynamicDirCache
180 CDynamicDirCache* CDynamicDirCache::NewL(TFatDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeLog2, const TDesC& aClientName)
182 // __PRINT3(_L("CDynamicDirCache::NewL(MinPageNum=%u, MaxPageNum=%u, page=%u)"), aMinPageNum, aMaxPageNum, 1<<aPageSizeLog2);
183 CDynamicDirCache* pSelf = new (ELeave) CDynamicDirCache(aDrive, aMinPageNum, aMaxPageNum, aPageSizeLog2);
184 CleanupStack::PushL(pSelf);
185 pSelf->ConstructL(aClientName);
191 Insert an unlocked page into the last position of the locked queue, may squeeze the original last page into
193 This function is used on last visited but 'unlocked' pages to avoid excessive lock/unlock calls to cache memory
194 manager as contiguous entry reading/writing often happens on the same page.
195 @param aPage the page to be inserted.
196 @pre the page type of aPage should only be TDynamicDirCachePage::EUnknown
198 void CDynamicDirCache::MakePageLastLocked(TDynamicDirCachePage* aPage)
200 // this function should not be called on active pages
201 ASSERT(aPage->iType == TDynamicDirCachePage::EUnknown);
203 if (iLockedQ.IsEmpty())
205 // if locked queue is empty, add it onto the locked queue directly
206 AddFirstOntoQueue(aPage, TDynamicDirCachePage::ELocked);
210 // otherwise, we squeeze for the last position on locked queue
211 while (iLockedQCount + 1 >= iMinSizeInPages)
213 TDynamicDirCachePage* last = iLockedQ.Last();
216 AddFirstOntoQueue(last, TDynamicDirCachePage::EUnlocked);
219 // iLockedQCount + 1 < iMinSizeInPages
220 iLockedQ.AddLast(*aPage);
221 aPage->SetPageType(TDynamicDirCachePage::ELocked);
227 Read data from a single page. If the page is not found or not valid anymore, read media onto iActive page
229 @param aPos the starting position of the media address to be read.
230 @param aLength the length of the content to be read.
231 @param aDes the descriptor to contain the content.
232 @pre aLength should be no more than page size.
234 void CDynamicDirCache::ReadDataFromSinglePageL(TInt64 aPos, TInt aLength, TDes8& aDes)
236 //-- the data section is in the cache page entirely, take data directly from the cache
237 TDynamicDirCachePage* pPage = FindPageByPos(aPos);
240 // lock page before reading,
241 if (LockPage(pPage) != NULL)
244 aDes.Copy(pPage->PtrInPage(aPos), aLength);
246 // if page is from unlocked queue, insert it onto the last page of the locked
247 // queue. this is to avoid excessive locking and unlocking operations that is
248 // highly likely to happen for following reads.
249 if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
252 MakePageLastLocked(pPage);
255 else // page locking failed
257 ASSERT(pPage->PageType() == TDynamicDirCachePage::EUnlocked);
259 LookupTblRemove(pPage->StartPos());
268 // if page not found or page data not valid anymore, use active page to read data in
269 pPage = UpdateActivePageL(aPos);
271 aDes.Copy(pPage->PtrInPage(aPos), aLength);
276 //====================================================================
278 Implementation of pure virtual function.
279 @see MWTCacheInterface::ReadL()
281 void CDynamicDirCache::ReadL(TInt64 aPos, TInt aLength, TDes8& aDes)
286 // cache is disabled for debug purposes
287 __PRINT(_L("CDynamicDirCache disabled"));
288 User::LeaveIfError(iDrive.ReadNonCritical(aPos, aLength, aDes));
294 const TUint32 PageSz = iPageSizeInBytes;//-- cache page size
296 TInt64 pageStartMedPos = CalcPageStartPos(aPos);
297 const TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos); //-- number of bytes from aPos to the end of the page
299 // __PRINT5(_L("CDynamicDirCache::ReadL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, aLength, pageStartMedPos, PageSz, bytesToPageEnd);
300 // if all data needed is on a single page
301 if((TUint32)aLength <= bytesToPageEnd)
303 ReadDataFromSinglePageL(aPos, aLength, aDes);
305 // or data to be read cross cache page boundary or probably we have more than 1 page to read
308 __PRINT(_L("CDynamicDirCache::ReadL() CROSS PAGE!"));
309 TUint32 dataLen(aLength); //-- current data length
310 TInt64 currMediaPos(aPos); //-- current media position
312 //-- 1. read data that are already in the current page
313 ReadDataFromSinglePageL(currMediaPos, bytesToPageEnd, aDes);
314 dataLen -= bytesToPageEnd;
315 currMediaPos += bytesToPageEnd;
317 TPtr8 dataNext = aDes.MidTPtr(aDes.Length());
319 //-- 2. read whole pages of data
320 while (dataLen >= PageSz)
322 //-- find out if currMediaPos is in cache. If not, find a spare page and read data there
323 ReadDataFromSinglePageL(currMediaPos, PageSz, dataNext);
324 currMediaPos += PageSz;
326 dataNext = dataNext.MidTPtr(dataNext.Length());
329 //-- 3. read the rest of the data
332 ReadDataFromSinglePageL(currMediaPos, dataLen, dataNext);
334 } //else((TUint32)aLength <= bytesToPageEnd)
338 Write data through a single page. If the page is not found or not valid anymore, read media onto iActive page
339 first, then write data through iActive page.
340 @param aPos the starting position of the media address to be write.
341 @param aData the starting address that the writing content lives in the ram.
342 @param aDataLen the length of the content to be written.
343 @pre aDataLen should be no more than page size.
345 void CDynamicDirCache::WriteDataOntoSinglePageL(TInt64 aPos, const TUint8* aData, TUint32 aDataLen)
347 ASSERT(aDataLen <= iPageSizeInBytes);
348 //-- the data section is in the cache page entirely, take data directly from the cache
349 TDynamicDirCachePage* pPage = FindPageByPos(aPos);
352 // lock page before writing,
353 if (LockPage(pPage) != NULL)
356 Mem::Copy(pPage->PtrInPage(aPos), aData, aDataLen);
360 ASSERT(pPage->PageType() == TDynamicDirCachePage::EUnlocked);
362 LookupTblRemove(pPage->StartPos());
369 // if page not found or page data not valid anymore, use active page to read data in
372 pPage = UpdateActivePageL(aPos);
374 Mem::Copy(pPage->PtrInPage(aPos), aData, aDataLen);
377 // make sure the page is unlocked after use
378 if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
383 // always make writting events MRU
389 Implementation of pure virtual function.
390 @see MWTCacheInterface::WriteL()
392 void CDynamicDirCache::WriteL(TInt64 aPos,const TDesC8& aDes)
397 // cache is disabled for debug purposes
398 __PRINT(_L("CDynamicDirCache disabled"));
399 User::LeaveIfError(iDrive.WriteCritical(aPos,aDes));
404 TUint32 dataLen = aDes.Size();
405 const TUint8* pData = aDes.Ptr();
406 const TUint32 PageSz = iPageSizeInBytes; //-- cache page size
408 TInt64 pageStartMedPos = CalcPageStartPos(aPos);
409 TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos);
411 // __PRINT5(_L("CDynamicDirCache::WriteL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, dataLen, pageStartMedPos, PageSz, bytesToPageEnd);
413 if(dataLen <= bytesToPageEnd)
415 WriteDataOntoSinglePageL(aPos, pData, dataLen);
419 __PRINT(_L("CDynamicDirCache::WriteL() CROSS PAGE!"));
421 //-- Data to be written cross cache page boundary or probably we have more than 1 page to write
422 TInt64 currMediaPos(aPos);
424 //-- 1. update the current page
425 WriteDataOntoSinglePageL(currMediaPos, pData, bytesToPageEnd);
427 pData += bytesToPageEnd;
428 currMediaPos += bytesToPageEnd;
429 dataLen -= bytesToPageEnd;
431 //-- 2. write whole pages of data to the cache
432 while (dataLen >= PageSz)
434 WriteDataOntoSinglePageL(currMediaPos, pData, PageSz);
437 currMediaPos += PageSz;
441 //-- 3. write the rest of the data
444 WriteDataOntoSinglePageL(currMediaPos, pData, dataLen);
446 }// else(dataLen <= bytesToPageEnd)
449 //-- write data to the media
450 const TInt nErr = iDrive.WriteCritical(aPos,aDes);
452 {//-- some serious problem occured during writing, invalidate cache.
459 Implementation of pure virtual function.
460 @see MWTCacheInterface::InvalidateCache()
462 void CDynamicDirCache::InvalidateCache(void)
464 __PRINT2(_L("CDynamicDirCache::InvalidateCache(locked=%d, unlocked=%d)"), iLockedQCount, iUnlockedQCount);
465 // we should never decommit locked pages as they needs to be reserved anyway
466 // the overhead of unnecessary page committing operations
467 while(!iLockedQ.IsEmpty())
469 TDynamicDirCachePage* page = iLockedQ.Last();
470 DeQueue(page); // remove from queue
471 LookupTblRemove(page->StartPos()); // remove from lookuptable
474 ASSERT(iLockedQCount == 0);
476 // however we should decommit unlocked pages here
477 while (!iUnlockedQ.IsEmpty())
479 TDynamicDirCachePage* page = iUnlockedQ.Last();
480 DeQueue(page); // remove from queue
481 LookupTblRemove(page->StartPos()); // remove from lookuptable
482 DecommitPage(page); // inform cache client to decommit page memory
485 ASSERT(iUnlockedQCount == 0);
487 ASSERT(iLookupTable.Count() == 0);
488 iLookupTable.Close();
490 ASSERT(iCacheMemoryClient);
492 // initialize cache state.
493 // Note that once the client is reset, all pages lose connection with the client
494 // including the active page. So we will need to reset and re-allocate active page
496 if (iCacheMemoryClient)
497 iCacheMemoryClient->Reset();
499 // reset and re-allocate active page
500 ResetPagePos(iActivePage); // reset start media position (0), invalidate page content
501 TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs());
502 // this should always succeed as the client has just been reset and there are always reserved pages
503 ASSERT(startRamAddr);
504 iActivePage->SetStartPtr(startRamAddr); // set RAM address
508 /** this method isn't implemented*/
509 void CDynamicDirCache::InvalidateCachePage(TUint64 /*aPos*/)
516 Implementation of pure virtual function.
517 @see MWTCacheInterface::PosCached()
519 TUint32 CDynamicDirCache::PosCached(const TInt64& aPos, TInt64& aCachedPosStart)
521 const TInt64 pageStartMedPos = CalcPageStartPos(aPos);
523 // only search the page in lookup table
524 // NOTE: we don't count the active page into acount here,
525 // this is to avoid pulling next pages recursively
526 TDynamicDirCachePage* pPage = LookupTblFind(pageStartMedPos);
528 // then check if page is still valid if page is on Unlocked Page Queue
529 if (pPage && pPage->PageType() == TDynamicDirCachePage::EUnlocked)
531 if (LockPage(pPage) != NULL)
533 // __PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) found on Unlocked Queue!"), aPos);
534 // have to unlock it before returning, otherwise there will be memory leak
536 aCachedPosStart = pPage->StartPos();
537 return pPage->PageSizeInBytes();
539 else // if the unlocked page is not valid anymore, remove it
542 LookupTblRemove(pPage->StartPos());
548 // otherwise if page is already locked or valid active page
551 __PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) on Locked Queue!"), aPos);
552 aCachedPosStart = pPage->StartPos();
553 return pPage->PageSizeInBytes();
556 // page is not found or not valid anymore
561 Implementation of pure virtual function.
562 @see MWTCacheInterface::CacheSizeInBytes()
564 TUint32 CDynamicDirCache::CacheSizeInBytes() const
566 return iMaxCacheSizeInBytes;
570 Implementation of pure virtual function.
571 @see MWTCacheInterface::Control()
573 TInt CDynamicDirCache::Control(TUint32 aFunction, TUint32 aParam1, TAny* aParam2)
575 TInt r = KErrNotSupported;
580 // disable / enable cache, for debug
581 // if aParam1 != 0 cache will be disabled, enabled otherwise
583 iCacheDisabled = aParam1 ? 1 : 0;
587 // dump cache, for debug
592 const TUint32 debugRegister = DebugRegister();
593 fs.SetDebugRegister(debugRegister|KFSYS);
595 fs.SetDebugRegister(debugRegister);
603 const TUint32 debugRegister = DebugRegister();
604 fs.SetDebugRegister(debugRegister|KFSYS);
606 fs.SetDebugRegister(debugRegister);
612 __PRINT1(_L("CDynamicDirCache::Control() invalid function: %d"), aFunction);
618 (void)aFunction; //-- supress warnings
621 User::Invariant(); //-- don't call this method in release build
628 Implementation of pure virtual function.
629 @see MWTCacheInterface::SetCacheBasePos()
631 void CDynamicDirCache::SetCacheBasePos(TInt64 aBasePos)
633 iCacheBasePos = aBasePos;
637 Implementation of pure virtual function.
638 @see MWTCacheInterface::SetCacheBasePos()
640 TUint32 CDynamicDirCache::PageSizeInBytesLog2() const
642 return iPageSizeLog2;
646 Implementation of pure virtual function.
647 @see MWTCacheInterface::MakePageMRU()
649 void CDynamicDirCache::MakePageMRU(TInt64 aPos)
651 __PRINT1(_L("MakePageMRU (%lx)"), aPos);
652 // __PRINT4(_L("Current Cache State: iLockedQCount=%d, iUnlockedQCount=%d, iLookupTbl=%d, iMaxSizeInPages=%d"), iLockedQCount, iUnlockedQCount, iLookupTable.Count(), iMaxSizeInPages);
653 // check the MRU page first, if it is already the MRU page, we can return immediately
654 TInt64 pageStartMedPos = CalcPageStartPos(aPos);
655 if (!iLockedQ.IsEmpty())
657 if (iLockedQ.First()->StartPos() == pageStartMedPos)
663 TDynamicDirCachePage* pPage = FindPageByPos(aPos);
666 ASSERT(pPage->IsValid());
667 // lock page before make it MRU
668 if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
670 ASSERT(!pPage->IsLocked());
671 if (LockPage(pPage) == NULL)
674 LookupTblRemove(pPage->StartPos());
682 // error checking: page should either be locked or active
683 ASSERT(LockPage(pPage) != NULL);
687 // if page not found or page data not valid anymore, use active page to read data
690 TRAPD(err, pPage = UpdateActivePageL(aPos));
693 // problem occurred reading active page, return immediately.
698 // by now, the page is either locked or active page
699 ASSERT(pPage && pPage->IsValid() && pPage->IsLocked());
701 switch (pPage->PageType())
703 // if the page is the active page, we will need to find a new active page for replacement
704 case TDynamicDirCachePage::EActivePage:
706 TDynamicDirCachePage* newAP = NULL;
707 // if there is more cache room available, try to create a new page first
710 // allocate and lock a new page
711 TRAPD(err, newAP = AllocateAndLockNewPageL(0));
712 // if any error ocurrs, return immediately
715 // unlock the page that was originally unlocked before leave
716 if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
725 // replace the active page with the new page
726 newAP->SetPageType(TDynamicDirCachePage::EActivePage);
731 // if cache has grown to its max size, or new page allocation failed
734 // try to lock the LRU page on the unlocked page queque first
735 if (!iUnlockedQ.IsEmpty())
737 newAP = iUnlockedQ.Last();
738 ASSERT(newAP->IsValid());
739 if (LockPage(newAP) != NULL)
741 // deque, reset pos, set new type
743 LookupTblRemove(newAP->StartPos());
745 newAP->SetPageType(TDynamicDirCachePage::EActivePage);
746 // replace active page
749 // if falied locking the LRU page from unclocked queque,
754 LookupTblRemove(newAP->StartPos());
762 // if still have not found new active page
763 // grab the LRU page from Locked Page Queue for active page
766 ASSERT(!iLockedQ.IsEmpty());
767 newAP = iLockedQ.Last();
768 // deque, reset pos, set new type
770 LookupTblRemove(newAP->StartPos());
772 newAP->SetPageType(TDynamicDirCachePage::EActivePage);
773 // replace active page
777 // we should always be able to find a locked page for active page
778 ASSERT(newAP != NULL);
780 // make original page (i.e. former active page) MRU
781 // add onto locked queue
782 AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
783 // add onto lookuptbl, as active page is not on lookup tbl originally
789 case TDynamicDirCachePage::EUnlocked:
791 // if page was originally on Unlocked Page Queque, remove it from Unlocked Page Queue, add it
792 // to the Locked Page Queue and make it MRU
794 AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
799 case TDynamicDirCachePage::ELocked:
801 // otherwise the page was on Locked Page Queue, make it MRU
802 // no need to check cache limit
803 if (pPage != iLockedQ.First())
806 AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
816 //====================================================================
818 Internal query function, to check if aPos is cached or not. iActive page is included in searching.
820 TDynamicDirCachePage* CDynamicDirCache::FindPageByPos(TInt64 aPos)
822 __PRINT1(_L("CDynamicDirCache::FindPageByPos(aPos=%lx)"), aPos);
823 // align the page position
824 TInt64 pageStartMedPos = CalcPageStartPos(aPos);
826 if ((iActivePage->StartPos() == pageStartMedPos))
828 ASSERT(iActivePage->IsValid());
832 // search in lookup table
833 return LookupTblFind(pageStartMedPos);
837 read a page length data into iActive page and return iActive page if read is successful.
839 TDynamicDirCachePage* CDynamicDirCache::UpdateActivePageL(TInt64 aPos)
841 // align the page position
842 TInt64 pageStartMedPos = CalcPageStartPos(aPos);
844 if (iActivePage->StartPos() == pageStartMedPos && iActivePage->IsValid())
849 __PRINT2(_L("CDynamicDirCache::UpdateActivePageL(aPos=%lx, active=%lx)"), aPos, iActivePage->StartPos());
851 // set start med pos value, no other effects, only available to active page
852 iActivePage->SetPos(pageStartMedPos);
854 // read data, make active page valid
855 TUint8* data = iActivePage->PtrInPage(iActivePage->iStartMedPos);
856 TPtr8 dataPtr(data, iPageSizeInBytes);
857 const TInt nErr = iDrive.ReadNonCritical(iActivePage->iStartMedPos, iPageSizeInBytes, dataPtr);
860 // some serious problem occured during reading, invalidate cache.
864 iActivePage->SetValid(ETrue);
870 Check if the number of (locked pages + iActive page) and unlocked pages have exceeded minimum allowed page
871 number and maximum allowed page number respectively.
873 void CDynamicDirCache::CheckThresholds()
875 while (iLockedQCount + 1 > iMinSizeInPages)
877 TDynamicDirCachePage* movePage = iLockedQ.Last();
878 UnlockPage(movePage);
880 TInt err = LookupTblRemove(movePage->StartPos());
881 ASSERT(err == KErrNone);
883 // if it is a valid page, add onto unlocked queue
884 if (movePage->StartPos() != 0)
886 ASSERT(movePage->IsValid());
887 AddFirstOntoQueue(movePage, TDynamicDirCachePage::EUnlocked);
888 err = LookupTblAdd(movePage);
889 ASSERT(err == KErrNone);
891 else // reserved page, delete
893 DecommitPage(movePage);
898 // if unlocked queue exceeds limit, delete LRU page
899 // note: all pages on unlocked queue should be valid
900 while (iUnlockedQCount > iMaxSizeInPages - iMinSizeInPages)
902 TDynamicDirCachePage* removePage = iUnlockedQ.Last();
903 ASSERT(removePage->StartPos() != 0 && removePage->IsValid());
905 LookupTblRemove(removePage->StartPos());
906 DecommitPage(removePage);
912 Try to create a new page and lock the page content when it is created. This function should only be called
913 when creating iActive page or making a page MRU (which might result in page evictions).
914 @return the pointer of the newly created page, or NULL if allocation failed.
915 @param aStartMedPos the starting media address of the page to be created.
916 @pre aStartMedPos should not already be existing in the cache.
918 TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPageL(TInt64 aStartMedPos)
920 __PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPageL(aStartMedPos=%lx)"), aStartMedPos);
922 TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs());
925 // create new page and return
926 TDynamicDirCachePage* pPage = TDynamicDirCachePage::NewL(this, aStartMedPos, startRamAddr);
927 pPage->SetLocked(ETrue);
928 pPage->SetValid(EFalse);
937 Dump cache information, only enabled in debug mode.
938 @see CDynamicDirCache::Control()
940 void CDynamicDirCache::Info() const
942 __PRINT(_L("======== CDynamicDirCache::Info ========="));
943 const TUint32 SegmentSizeInBytesLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2();
945 __PRINT1(_L("=== Pages size: [%d Bytes]"), iPageSizeInBytes);
946 __PRINT1(_L("=== Segment size: [%d Bytes]"), 1 << SegmentSizeInBytesLog2);
949 __PRINT1(_L("=== Min data size: [%d Bytes]"), iMinSizeInPages << iPageSizeLog2);
950 __PRINT1(_L("=== Max data size: [%d Bytes]"), iMaxSizeInPages << iPageSizeLog2);
953 const TUint32 pageMemSizeLog2 = iPageSizeLog2 > SegmentSizeInBytesLog2 ? iPageSizeLog2 : SegmentSizeInBytesLog2;
954 __PRINT1(_L("=== Min memory size: [%d Bytes]"), iMinSizeInPages << pageMemSizeLog2);
955 __PRINT1(_L("=== Max memory size: [%d Bytes]"), iMaxSizeInPages << pageMemSizeLog2);
958 __PRINT1(_L("=== Number of pages reserved: [%d]"), iMinSizeInPages);
959 __PRINT1(_L("=== Reserved memory: [%d Bytes]"), (iMinSizeInPages * PageSizeInSegs()) << SegmentSizeInBytesLog2);
961 __PRINT1(_L("=== Number of pages locked: [%d]"), iLockedQCount);
962 __PRINT1(_L("=== Locked memory: [%d Bytes]"), (iLockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2);
964 __PRINT1(_L("=== Number of pages unlocked: [%d]"), iUnlockedQCount);
965 __PRINT1(_L("=== Unlocked memory: [%d Bytes]"), (iUnlockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2);
969 Dump cache content, only enabled in debug mode.
970 @see CDynamicDirCache::Control()
972 void CDynamicDirCache::Dump()
974 __PRINT(_L("======== CDynamicDirCache::Dump ========="));
975 if (!iLockedQ.IsEmpty())
977 TDblQueIter<TDynamicDirCachePage> q(iLockedQ);
980 while((TDynamicDirCachePage*)q)
982 TDynamicDirCachePage* pP = q++;
983 __PRINT3(_L("=== CDynamicDirCache::iLockedQ\t[%4d](pos=%lx, size=%d)"), i++, pP->StartPos(), pP->PageSizeInBytes());
986 if (!iUnlockedQ.IsEmpty())
988 TDblQueIter<TDynamicDirCachePage> q(iUnlockedQ);
991 while((TDynamicDirCachePage*)q)
993 TDynamicDirCachePage* pP = q++;
994 __PRINT3(_L("=== CDynamicDirCache::iUnlockedQ\t[%4d](pos=%lx, size=%u)"), i++, pP->StartPos(), pP->PageSizeInBytes());
997 __PRINT2(_L("=== CDynamicDirCache::iActivePage\t[*](pos=%lx, size=%u)"), iActivePage->StartPos(), iActivePage->PageSizeInBytes());
999 if (iLookupTable.Count())
1002 THashSetIter<TLookupEntry> iter(iLookupTable);
1003 TLookupEntry* pEntry;
1004 pEntry = (TLookupEntry*) iter.Next();
1007 TDynamicDirCachePage* pP = pEntry->iPage;
1008 __PRINT3(_L("=== CDynamicDirCache::iLookupTable\t[%4d](pos=%lx, size=%u)"), i++, pP->StartPos(), pP->PageSizeInBytes());
1009 pEntry = (TLookupEntry*) iter.Next();
1012 __PRINT(_L("===========================================\n"));
1017 Lock an unlocked page, or do nothing if the page is already locked.
1018 @return TUint8* pointer of the page to be locked, if locking is successful, otherwise return NULL.
1019 @param aPage the pointer of the page to be locked.
1021 TUint8* CDynamicDirCache::LockPage(TDynamicDirCachePage* aPage)
1023 ASSERT(aPage != NULL);
1024 if (aPage->IsLocked())
1025 return aPage->StartPtr();
1027 TInt r = iCacheMemoryClient->LockSegments(aPage->StartPtr(), PageSizeInSegs());
1030 aPage->SetLocked(ETrue);
1031 return aPage->StartPtr();
1038 Unlock a locked page.
1039 @return TInt KErrNone if unlocking was successful, otherwise system-wide error code.
1040 @param aPage the pointer of the page to be unlocked.
1042 TInt CDynamicDirCache::UnlockPage(TDynamicDirCachePage* aPage)
1044 ASSERT(aPage != NULL);
1045 __PRINT1(_L("CDynamicDirCache::UnlockPage(%lx)"), aPage->StartPos());
1046 TInt r = iCacheMemoryClient->UnlockSegments(aPage->StartPtr(), PageSizeInSegs());
1049 aPage->SetLocked(EFalse);
1055 Decommit a locked or unlocked page.
1056 @return TInt KErrNone if decommition was successful, otherwise system-wide error code.
1057 @param aPage the pointer of the page to be decommitted.
1059 TInt CDynamicDirCache::DecommitPage(TDynamicDirCachePage* aPage)
1061 ASSERT(aPage != NULL);
1062 __PRINT1(_L("CDynamicDirCache::DecommitPage(%lx)"), aPage->StartPos());
1065 TInt r = iCacheMemoryClient->DecommitSegments(aPage->StartPtr(), PageSizeInSegs());
1068 aPage->SetLocked(EFalse);
1069 aPage->SetValid(EFalse);
1073 return KErrArgument;
1076 /////////////////////////// aluxiliary functions //////////////////////////////////
1078 Calculate the page size in segments. Segment size is the size of the kernel memory unit that cache memory manager manages.
1079 We are making assumption here about the page size: page size should always be either less than segment size
1080 or multiple times of segment size
1081 @return TUint32 the page size in segments.
1083 TUint32 CDynamicDirCache::PageSizeInSegs() const
1085 // initialize cache memory manager as all file systems have mounted by now
1086 ASSERT(CCacheMemoryManagerFactory::CacheMemoryManager());
1087 const TUint32 SegmentSizeInBytesLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2();
1089 // Page size should be non-zero
1090 ASSERT(iPageSizeInBytes);
1092 TUint32 segs = iPageSizeInBytes >> SegmentSizeInBytesLog2;
1093 return segs > 0 ? segs : 1;
1097 Deque the page from locked queue or unlocked queue. All pages are managed through these two queues, expect iActive
1099 @param aPage the pointer of the page to be dequeued
1100 @return TInt KErrArgument if aPage is invalid, otherwise KErrNone.
1102 TInt CDynamicDirCache::DeQueue(TDynamicDirCachePage* aPage)
1106 return KErrArgument;
1108 if (aPage->iType == TDynamicDirCachePage::ELocked)
1111 aPage->SetPageType(TDynamicDirCachePage::EUnknown);
1114 else if (aPage->iType == TDynamicDirCachePage::EUnlocked)
1117 aPage->SetPageType(TDynamicDirCachePage::EUnknown);
1123 return KErrArgument;
1129 Insert a page to the first position of locked queue or unlocked queue.
1130 @param aPage the pointer of the page to be inserted.
1131 @param aType the type of the queue to be inserted.
1132 @return TInt KErrArgument if aPage is invalid, otherwise KErrNone.
1134 TInt CDynamicDirCache::AddFirstOntoQueue(TDynamicDirCachePage* aPage, TDynamicDirCachePage::TPageType aType)
1138 return KErrArgument;
1140 // page must be dequed first or it is active page
1141 if (aPage->iType != TDynamicDirCachePage::EActivePage && aPage->iType != TDynamicDirCachePage::EUnknown)
1144 return KErrArgument;
1147 if (aType == TDynamicDirCachePage::ELocked)
1149 iLockedQ.AddFirst(*aPage);
1150 aPage->SetPageType(TDynamicDirCachePage::ELocked);
1153 else if (aType == TDynamicDirCachePage::EUnlocked)
1155 iUnlockedQ.AddFirst(*aPage);
1156 aPage->SetPageType(TDynamicDirCachePage::EUnlocked);
1162 return KErrArgument;
1169 Remove a page from the lookup table, indexed by the starting media address of the page content.
1170 @param aPagePos the starting media position of the page to be removed.
1172 TInt CDynamicDirCache::LookupTblRemove(TInt64 aPagePos)
1179 TInt r = iLookupTable.Remove(TLookupEntry(aPagePos, 0, NULL));
1184 Insert a page to the lookup table, indexed by the starting media address of the page content.
1185 @param aPagePos the starting media position of the page to be inserted.
1187 TInt CDynamicDirCache::LookupTblAdd(TDynamicDirCachePage* aPage)
1191 return KErrArgument;
1193 if (aPage->StartPos() == 0)
1198 TInt r = iLookupTable.Insert(TLookupEntry(aPage->StartPos(), iPageSizeInBytes, aPage));
1203 Reset the media address of the page to 0, also invalidate the page.
1204 @param aPage the pointer of the page to be reset.
1206 TInt CDynamicDirCache::ResetPagePos(TDynamicDirCachePage* aPage)
1210 return KErrArgument;
1217 Search the lookup table to find the page start with a specific media address.
1218 @param aPos the starting media address to be searched.
1220 TDynamicDirCachePage* CDynamicDirCache::LookupTblFind(TInt64 aPos)
1228 TLookupEntry* entry = iLookupTable.Find(TLookupEntry(aPos, 0, NULL));
1231 ASSERT(entry->iPage->IsValid());
1232 return entry->iPage;