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
19 #include "sl_dir_cache.h"
21 //======================================================================
22 TDynamicDirCachePage::~TDynamicDirCachePage()
27 The static cache page creation function.
28 Cache page objects are not supposed to be created on the stack, so this factory function is required.
30 TDynamicDirCachePage* TDynamicDirCachePage::NewL(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
32 return new(ELeave) TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr);
36 Cache page constructor.
37 @param aOwnerCache pointer of the cache that owns this page
38 @param aStartMedPos the start address on the media that this page caches
39 @param aStartRamAddr the start address in the ram that this page content lives
41 TDynamicDirCachePage::TDynamicDirCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
42 :iStartMedPos(aStartMedPos),
43 iStartRamAddr(aStartRamAddr),
44 iOwnerCache(aOwnerCache),
48 //__PRINT3(_L("TDynamicDirCachePage::TDynamicDirCachePage(aStartMedPos=%lx, aStartRamAddr=0x%X, aPageSize=%u)"), aStartMedPos, aStartRamAddr, PageSizeInBytes());
52 /////////////////////////////// class CDynamicDirCache::TLookupEntry ///////////////////////////
54 Required by RHashSet<TLookupEntry> to identify individual hash set entries.
57 TBool IdentityFunction(const TLookupEntry& aEntry1, const TLookupEntry& aEntry2)
59 // only check starting med pos for hash searching
60 return aEntry1.iPos == aEntry2.iPos;
63 Required by RHashSet<TLookupEntry> to generate hash value.
66 TUint32 HashFunction(const TLookupEntry& aEntry)
68 return (DefaultHash::Integer(I64HIGH(aEntry.iPos)) + DefaultHash::Integer(I64LOW(aEntry.iPos)));
71 /////////////////////////////// class CDynamicDirCache ///////////////////////////
72 CDynamicDirCache::~CDynamicDirCache()
74 __PRINT(_L("CDynamicDirCache::~CDynamicDirCache()"));
76 // we should never decommit locked pages
77 while (!iLockedQ.IsEmpty())
79 TDynamicDirCachePage* page = iLockedQ.Last();
80 DeQueue(page); // remove from queue
81 LookupTblRemove(page->StartPos()); // remove from lookuptable
84 ASSERT(iLockedQCount == 0);
86 while (!iUnlockedQ.IsEmpty())
88 TDynamicDirCachePage* page = iUnlockedQ.Last();
89 DeQueue(page); // remove from queue
90 LookupTblRemove(page->StartPos()); // remove from lookuptable
91 DecommitPage(page); // inform cache client to decommit page memory
94 ASSERT(iUnlockedQCount == 0);
96 ASSERT(iLookupTable.Count() == 0);
98 if (iCacheMemoryClient)
99 iCacheMemoryClient->Reset();
103 Constructor of CDynamicDirCache.
104 @param aDrive local drive interface to read/write media
105 @param aMinPageNum the minimum page number for the cache, includes iActive page and locked pages.
106 @param aMaxPageNum the maximum page number for the cache, includes iActive page, locked pages and unlocked pages.
107 @param aPageSizeInBytesLog2 the log2 value of page size in bytes, assumes page size is always a power of two
109 CDynamicDirCache::CDynamicDirCache(TDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeInBytesLog2)
110 :iPageSizeLog2(aPageSizeInBytesLog2),
111 iMinSizeInPages(aMinPageNum),
112 iMaxSizeInPages(aMaxPageNum),
114 iLockedQ(_FOFF(TDynamicDirCachePage, iLink)),
115 iUnlockedQ(_FOFF(TDynamicDirCachePage, iLink)),
118 iHashFunction(HashFunction),
119 iIdentityFunction(IdentityFunction),
120 iLookupTable(iHashFunction, iIdentityFunction)
122 iPageSizeInBytes = 1 << aPageSizeInBytesLog2;
123 iCacheDisabled = EFalse;
124 iMinCacheSizeInBytes = aMinPageNum << aPageSizeInBytesLog2;
125 iMaxCacheSizeInBytes = aMaxPageNum << aPageSizeInBytesLog2;
126 ASSERT(iPageSizeInBytes && iPageSizeInBytes <= iMinCacheSizeInBytes && iMinCacheSizeInBytes <= iMaxCacheSizeInBytes);
127 // initial value, will be reset from outside
132 Second phase constructor of CDynamicDirCache.
133 @param aClientName the identification of cache memeory client this cache connects
135 void CDynamicDirCache::ConstructL(const TDesC& aClientName)
137 // __PRINT3(_L("CDynamicDirCache::ConstructL(Min=%u, Max=%u, page=%u)"), iMinCacheSizeInBytes, iMaxCacheSizeInBytes, iPageSizeInBytes);
138 CCacheMemoryManager* manager = CCacheMemoryManagerFactory::CacheMemoryManager();
141 // client will register itself onto cache memory manager when created
142 // note this operation may leave under OOM condition
143 iCacheMemoryClient = manager->ConnectClientL(aClientName, iMinSizeInPages * PageSizeInSegs(), iMaxSizeInPages * PageSizeInSegs());
147 User::Leave(KErrNotSupported);
150 ASSERT(iCacheMemoryClient);
151 if (!iCacheMemoryClient)
153 User::Leave(KErrNoMemory);
157 // allocate as many permanently locked pages as there are threads - plus one
158 // otherwise DoMakePageMRU() won't work properly with only one thread
159 //-- At present moment the size of TDrive thread pool is 1 (1 drive thread in a pool)
160 iPermanentlyAllocatedPageCount = 1;
162 if (iPermanentlyAllocatedPageCount > iMinSizeInPages)
163 iMinSizeInPages = iPermanentlyAllocatedPageCount;
165 for (TUint n=0; n<iPermanentlyAllocatedPageCount; n++)
167 TDynamicDirCachePage* pPage = AllocateAndLockNewPageL(0);
168 AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
175 Static factory function of CDynamicDirCache
177 CDynamicDirCache* CDynamicDirCache::NewL(TDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeLog2, const TDesC& aClientName)
179 __PRINT3(_L("CDynamicDirCache::NewL(MinPageNum=%u, MaxPageNum=%u, page=%u)"), aMinPageNum, aMaxPageNum, 1<<aPageSizeLog2);
180 CDynamicDirCache* pSelf = new (ELeave) CDynamicDirCache(aDrive, aMinPageNum, aMaxPageNum, aPageSizeLog2);
181 CleanupStack::PushL(pSelf);
182 pSelf->ConstructL(aClientName);
188 Insert an unlocked page into the last position of the locked queue, may squeeze the original last page into
190 This function is used on last visited but 'unlocked' pages to avoid excessive lock/unlock calls to cache memory
191 manager as contiguous entry reading/writing often happens on the same page.
192 @param aPage the page to be inserted.
193 @pre the page type of aPage should only be TDynamicDirCachePage::EUnknown
195 void CDynamicDirCache::MakePageLastLocked(TDynamicDirCachePage* aPage)
197 // this function should not be called on active pages
198 ASSERT(aPage->iType == TDynamicDirCachePage::EUnknown);
200 if (iLockedQ.IsEmpty())
202 // if locked queue is empty, add it onto the locked queue directly
203 AddFirstOntoQueue(aPage, TDynamicDirCachePage::ELocked);
207 // otherwise, we squeeze for the last position on locked queue
208 while (iLockedQCount + 1 >= iMinSizeInPages)
210 TDynamicDirCachePage* last = iLockedQ.Last();
213 AddFirstOntoQueue(last, TDynamicDirCachePage::EUnlocked);
216 // iLockedQCount + 1 < iMinSizeInPages
217 iLockedQ.AddLast(*aPage);
218 aPage->SetPageType(TDynamicDirCachePage::ELocked);
224 Read data from a single page. If the page is not found or not valid anymore, read media onto iActive page first.
225 The data will be _Appended_ the the descriptor aDes. The caller is responsible for maintaining this descriptor.
227 @param aPos the starting position of the media address to be read.
228 @param aLength the length of the content to be read.
229 @param aDes the descriptor to contain the content.
230 @pre aLength should be no more than page size.
232 void CDynamicDirCache::ReadDataFromSinglePageL(TInt64 aPos, TInt aLength, TDes8& aDes)
234 //-- the data section is in the cache page entirely, take data directly from the cache
235 TDynamicDirCachePage* pPage = FindPageByPos(aPos);
238 // lock page before reading,
239 if (LockPage(pPage) != NULL)
241 // read data and append them to the descriptor
242 aDes.Append(pPage->PtrInPage(aPos), aLength);
245 // if page is from unlocked queue, insert it onto the last page of the locked
246 // queue. this is to avoid excessive locking and unlocking operations that is
247 // highly likely to happen for following reads.
248 if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
251 MakePageLastLocked(pPage);
254 else // page locking failed
256 ASSERT(pPage->PageType() == TDynamicDirCachePage::EUnlocked);
258 LookupTblRemove(pPage->StartPos());
267 // if page not found or page data not valid anymore, use active page to read data in
268 pPage = UpdateActivePageL(aPos);
269 // read data and append them to the descriptor
270 aDes.Append(pPage->PtrInPage(aPos), aLength);
275 //====================================================================
277 Implementation of pure virtual function.
278 @see MWTCacheInterface::ReadL()
280 void CDynamicDirCache::ReadL(TInt64 aPos, TInt aLength, TDes8& aDes)
285 // cache is disabled for debug purposes
286 __PRINT(_L("CDynamicDirCache disabled"));
287 User::LeaveIfError(iDrive.ReadNonCritical(aPos, aLength, aDes));
293 const TUint32 PageSz = iPageSizeInBytes;//-- cache page size
295 TInt64 pageStartMedPos = CalcPageStartPos(aPos);
296 const TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos); //-- number of bytes from aPos to the end of the page
298 // __PRINT5(_L("CDynamicDirCache::ReadL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, aLength, pageStartMedPos, PageSz, bytesToPageEnd);
299 // if all data needed is on a single page
300 if((TUint32)aLength <= bytesToPageEnd)
302 ReadDataFromSinglePageL(aPos, aLength, aDes);
304 // or data to be read cross cache page boundary or probably we have more than 1 page to read
307 __PRINT(_L("CDynamicDirCache::ReadL() CROSS PAGE!"));
308 TUint32 dataLen(aLength); //-- current data length
309 TInt64 currMediaPos(aPos); //-- current media position
311 //-- 1. read data that are already in the current page
312 ReadDataFromSinglePageL(currMediaPos, bytesToPageEnd, aDes);
313 dataLen -= bytesToPageEnd;
314 currMediaPos += bytesToPageEnd;
316 //-- 2. read whole pages of data
317 while (dataLen >= PageSz)
319 //-- find out if currMediaPos is in cache. If not, find a spare page and read data there
320 ReadDataFromSinglePageL(currMediaPos, PageSz, aDes);
321 currMediaPos += PageSz;
325 //-- 3. read the rest of the data
328 ReadDataFromSinglePageL(currMediaPos, dataLen, aDes);
330 } //else((TUint32)aLength <= bytesToPageEnd)
334 Write data through a single page. If the page is not found or not valid anymore, read media onto iActive page
335 first, then write data through iActive page.
336 @param aPos the starting position of the media address to be write.
337 @param aData the starting address that the writing content lives in the ram.
338 @param aDataLen the length of the content to be written.
339 @pre aDataLen should be no more than page size.
341 void CDynamicDirCache::WriteDataOntoSinglePageL(TInt64 aPos, const TUint8* aData, TUint32 aDataLen)
343 ASSERT(aDataLen <= iPageSizeInBytes);
344 //-- the data section is in the cache page entirely, take data directly from the cache
345 TDynamicDirCachePage* pPage = FindPageByPos(aPos);
348 // lock page before writing,
349 if (LockPage(pPage) != NULL)
352 Mem::Copy(pPage->PtrInPage(aPos), aData, aDataLen);
356 ASSERT(pPage->PageType() == TDynamicDirCachePage::EUnlocked);
358 LookupTblRemove(pPage->StartPos());
365 // if page not found or page data not valid anymore, use active page to read data in
368 pPage = UpdateActivePageL(aPos);
370 Mem::Copy(pPage->PtrInPage(aPos), aData, aDataLen);
373 // make sure the page is unlocked after use
374 if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
379 // always make writting events MRU
385 Implementation of pure virtual function.
386 @see MWTCacheInterface::WriteL()
388 void CDynamicDirCache::WriteL(TInt64 aPos,const TDesC8& aDes)
393 // cache is disabled for debug purposes
394 __PRINT(_L("CDynamicDirCache disabled"));
395 User::LeaveIfError(iDrive.WriteCritical(aPos,aDes));
400 TUint32 dataLen = aDes.Size();
401 const TUint8* pData = aDes.Ptr();
402 const TUint32 PageSz = iPageSizeInBytes; //-- cache page size
404 TInt64 pageStartMedPos = CalcPageStartPos(aPos);
405 TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos);
407 // __PRINT5(_L("CDynamicDirCache::WriteL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, dataLen, pageStartMedPos, PageSz, bytesToPageEnd);
409 if(dataLen <= bytesToPageEnd)
411 WriteDataOntoSinglePageL(aPos, pData, dataLen);
415 __PRINT(_L("CDynamicDirCache::WriteL() CROSS PAGE!"));
417 //-- Data to be written cross cache page boundary or probably we have more than 1 page to write
418 TInt64 currMediaPos(aPos);
420 //-- 1. update the current page
421 WriteDataOntoSinglePageL(currMediaPos, pData, bytesToPageEnd);
423 pData += bytesToPageEnd;
424 currMediaPos += bytesToPageEnd;
425 dataLen -= bytesToPageEnd;
427 //-- 2. write whole pages of data to the cache
428 while (dataLen >= PageSz)
430 WriteDataOntoSinglePageL(currMediaPos, pData, PageSz);
433 currMediaPos += PageSz;
437 //-- 3. write the rest of the data
440 WriteDataOntoSinglePageL(currMediaPos, pData, dataLen);
442 }// else(dataLen <= bytesToPageEnd)
445 //-- write data to the media
446 const TInt nErr = iDrive.WriteCritical(aPos,aDes);
448 {//-- some serious problem occured during writing, invalidate cache.
456 @see MWTCacheInterface::InvalidateCache()
458 void CDynamicDirCache::DoInvalidateCache(void)
460 __PRINT2(_L("CDynamicDirCache::InvalidateCache(locked=%d, unlocked=%d)"), iLockedQCount, iUnlockedQCount);
461 // we should never decommit locked pages as they needs to be reserved anyway
462 // the overhead of unnecessary page committing operations
464 TInt pagesToRemoveFromLockedQueue = iLockedQCount - iPermanentlyAllocatedPageCount;
466 for (n=0; n<pagesToRemoveFromLockedQueue; n++)
468 TDynamicDirCachePage* page = iLockedQ.Last();
469 DeQueue(page); // remove from queue
470 LookupTblRemove(page->StartPos()); // remove from lookuptable
471 DecommitPage(page); // inform cache client to decommit page memory
474 ASSERT(iLockedQCount == iPermanentlyAllocatedPageCount);
476 TDblQueIter<TDynamicDirCachePage> q(iLockedQ);
478 while((TDynamicDirCachePage*) q)
480 TDynamicDirCachePage* page = q++;
481 LookupTblRemove(page->StartPos());// remove from lookuptable
482 ResetPagePos(page); // reset start media position (0), invalidate page content
485 // however we should decommit unlocked pages here
486 while (!iUnlockedQ.IsEmpty())
488 TDynamicDirCachePage* page = iUnlockedQ.Last();
489 DeQueue(page); // remove from queue
490 LookupTblRemove(page->StartPos()); // remove from lookuptable
491 DecommitPage(page); // inform cache client to decommit page memory
494 ASSERT(iUnlockedQCount == 0);
496 ASSERT(iLockedQCount == iPermanentlyAllocatedPageCount);
498 ASSERT(iCacheMemoryClient);
502 Implementation of pure virtual function.
503 @see MWTCacheInterface::InvalidateCache()
505 void CDynamicDirCache::InvalidateCache(void)
510 /** this method isn't implemented*/
511 void CDynamicDirCache::InvalidateCachePage(TUint64 /*aPos*/)
518 Implementation of pure virtual function.
519 @see MWTCacheInterface::PosCached()
521 TUint32 CDynamicDirCache::PosCached(const TInt64& aPos, TInt64& aCachedPosStart)
523 const TInt64 pageStartMedPos = CalcPageStartPos(aPos);
525 // only search the page in lookup table
526 // NOTE: we don't count the active page into acount here,
527 // this is to avoid pulling next pages recursively
528 TDynamicDirCachePage* pPage = LookupTblFind(pageStartMedPos);
530 // then check if page is still valid if page is on Unlocked Page Queue
531 if (pPage && pPage->PageType() == TDynamicDirCachePage::EUnlocked)
533 if (LockPage(pPage) != NULL)
535 // __PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) found on Unlocked Queue!"), aPos);
536 // have to unlock it before returning, otherwise there will be memory leak
538 aCachedPosStart = pPage->StartPos();
539 return pPage->PageSizeInBytes();
541 else // if the unlocked page is not valid anymore, remove it
544 LookupTblRemove(pPage->StartPos());
550 // otherwise if page is already locked or valid active page
553 __PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) on Locked Queue!"), aPos);
554 aCachedPosStart = pPage->StartPos();
555 return pPage->PageSizeInBytes();
558 // page is not found or not valid anymore
563 Implementation of pure virtual function.
564 @see MWTCacheInterface::CacheSizeInBytes()
566 TUint32 CDynamicDirCache::CacheSizeInBytes() const
568 return iMaxCacheSizeInBytes;
572 Implementation of pure virtual function.
573 @see MWTCacheInterface::Control()
575 TInt CDynamicDirCache::Control(TUint32 aFunction, TUint32 aParam1, TAny* aParam2)
577 TInt r = KErrNotSupported;
582 // disable / enable cache, for debug
583 // if aParam1 != 0 cache will be disabled, enabled otherwise
585 iCacheDisabled = aParam1 ? 1 : 0;
589 // dump cache, for debug
594 const TUint32 debugRegister = DebugRegister();
595 fs.SetDebugRegister(debugRegister|KFSYS);
597 fs.SetDebugRegister(debugRegister);
605 const TUint32 debugRegister = DebugRegister();
606 fs.SetDebugRegister(debugRegister|KFSYS);
608 fs.SetDebugRegister(debugRegister);
614 __PRINT1(_L("CDynamicDirCache::Control() invalid function: %d"), aFunction);
620 (void)aFunction; //-- supress warnings
623 User::Invariant(); //-- don't call this method in release build
630 Implementation of pure virtual function.
631 @see MWTCacheInterface::SetCacheBasePos()
633 void CDynamicDirCache::SetCacheBasePos(TInt64 aBasePos)
635 iCacheBasePos = aBasePos;
639 Implementation of pure virtual function.
640 @see MWTCacheInterface::SetCacheBasePos()
642 TUint32 CDynamicDirCache::PageSizeInBytesLog2() const
644 return iPageSizeLog2;
648 void CDynamicDirCache::DoMakePageMRU(TInt64 aPos)
650 // __PRINT1(_L("MakePageMRU (%lx)"), aPos);
651 // __PRINT4(_L("Current Cache State: iLockedQCount=%d, iUnlockedQCount=%d, iLookupTbl=%d, iMaxSizeInPages=%d"), iLockedQCount, iUnlockedQCount, iLookupTable.Count(), iMaxSizeInPages);
652 // check the MRU page first, if it is already the MRU page, we can return immediately
653 TInt64 pageStartMedPos = CalcPageStartPos(aPos);
654 if (!iLockedQ.IsEmpty())
656 if (iLockedQ.First()->StartPos() == pageStartMedPos)
662 TDynamicDirCachePage* pPage = FindPageByPos(aPos);
665 ASSERT(pPage->IsValid());
666 // lock page before make it MRU
667 if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
669 ASSERT(!pPage->IsLocked());
670 if (LockPage(pPage) == NULL)
673 LookupTblRemove(pPage->StartPos());
681 // error checking: page should either be locked or active
682 ASSERT(LockPage(pPage) != NULL);
686 // if page not found or page data not valid anymore, use active page to read data
689 TRAPD(err, pPage = UpdateActivePageL(aPos));
692 // problem occurred reading active page, return immediately.
697 // by now, the page is either locked or active page
698 ASSERT(pPage && pPage->IsValid() && pPage->IsLocked());
702 TBool allocateNewPage = pPage == iLockedQ.Last() && !CacheIsFull();
705 switch (pPage->PageType())
707 case TDynamicDirCachePage::EUnlocked:
709 // if page was originally on Unlocked Page Queque, remove it from Unlocked Page Queue, add it
710 // to the Locked Page Queue and make it MRU
712 AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
716 case TDynamicDirCachePage::ELocked:
718 // otherwise the page was on Locked Page Queue, make it MRU
719 // no need to check cache limit
720 if (pPage != iLockedQ.First())
723 AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
733 TDynamicDirCachePage* nPage = NULL;
734 TRAPD(err, nPage = AllocateAndLockNewPageL(0));
738 // about to add a page to end of locked queue, so lie about iLockedQCount
743 iLockedQ.AddLast(*nPage);
744 nPage->SetPageType(TDynamicDirCachePage::ELocked);
752 Implementation of pure virtual function.
753 @see MDiskSpecialAccessor::MakePageMRU()
755 void CDynamicDirCache::MakePageMRU(TInt64 aPos)
760 //====================================================================
762 Internal query function, to check if aPos is cached or not. iActive page is included in searching.
764 TDynamicDirCachePage* CDynamicDirCache::FindPageByPos(TInt64 aPos)
766 // __PRINT1(_L("CDynamicDirCache::FindPageByPos(aPos=%lx)"), aPos);
767 // align the page position
768 TInt64 pageStartMedPos = CalcPageStartPos(aPos);
770 // search in lookup table
771 return LookupTblFind(pageStartMedPos);
775 read a page length data into iActive page and return iActive page if read is successful.
777 TDynamicDirCachePage* CDynamicDirCache::UpdateActivePageL(TInt64 aPos)
779 // align the page position
780 TInt64 pageStartMedPos = CalcPageStartPos(aPos);
782 ASSERT(!iLockedQ.IsEmpty());
783 TDynamicDirCachePage* activePage = iLockedQ.Last();
785 if (activePage->StartPos() == pageStartMedPos && activePage->IsValid())
790 __PRINT2(_L("CDynamicDirCache::UpdateActivePageL(aPos=%lx, active=%lx)"), aPos, activePage->StartPos());
793 LookupTblRemove(activePage->StartPos());
795 // set start med pos value, no other effects, only available to active page
796 activePage->SetPos(pageStartMedPos);
798 // read data, make active page valid
799 TUint8* data = activePage->PtrInPage(activePage->iStartMedPos);
800 TPtr8 dataPtr(data, iPageSizeInBytes);
802 const TInt nErr = iDrive.ReadNonCritical(activePage->iStartMedPos, iPageSizeInBytes, dataPtr);
804 iLockedQ.AddLast(*activePage);
805 LookupTblAdd(activePage);
809 // some serious problem occured during reading, invalidate cache.
813 activePage->SetValid(ETrue);
819 Check if the number of (locked pages + iActive page) and unlocked pages have exceeded minimum allowed page
820 number and maximum allowed page number respectively.
822 void CDynamicDirCache::CheckThresholds()
824 while (iLockedQCount + 1 > iMinSizeInPages)
826 TDynamicDirCachePage* movePage = iLockedQ.Last();
827 UnlockPage(movePage);
829 TInt err = LookupTblRemove(movePage->StartPos());
830 ASSERT(err == KErrNone);
832 // if it is a valid page, add onto unlocked queue
833 if (movePage->StartPos() != 0)
835 ASSERT(movePage->IsValid());
836 AddFirstOntoQueue(movePage, TDynamicDirCachePage::EUnlocked);
837 err = LookupTblAdd(movePage);
838 ASSERT(err == KErrNone);
840 else // reserved page, delete
842 DecommitPage(movePage);
847 // if unlocked queue exceeds limit, delete LRU page
848 // note: all pages on unlocked queue should be valid
849 while (iUnlockedQCount > iMaxSizeInPages - iMinSizeInPages)
851 TDynamicDirCachePage* removePage = iUnlockedQ.Last();
852 ASSERT(removePage->StartPos() != 0 && removePage->IsValid());
854 LookupTblRemove(removePage->StartPos());
855 DecommitPage(removePage);
861 Try to create a new page and lock the page content when it is created. This function should only be called
862 when creating iActive page or making a page MRU (which might result in page evictions).
863 @return the pointer of the newly created page, or NULL if allocation failed.
864 @param aStartMedPos the starting media address of the page to be created.
865 @pre aStartMedPos should not already be existing in the cache.
867 TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPageL(TInt64 aStartMedPos)
869 __PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPageL(aStartMedPos=%lx)"), aStartMedPos);
871 TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs());
874 // create new page and return
875 TDynamicDirCachePage* pPage = TDynamicDirCachePage::NewL(this, aStartMedPos, startRamAddr);
876 pPage->SetLocked(ETrue);
877 pPage->SetValid(EFalse);
886 Dump cache information, only enabled in debug mode.
887 @see CDynamicDirCache::Control()
889 void CDynamicDirCache::Info() const
891 __PRINT(_L("======== CDynamicDirCache::Info ========="));
892 const TUint32 SegmentSizeInBytesLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2();
894 __PRINT1(_L("=== Pages size: [%d Bytes]"), iPageSizeInBytes);
895 __PRINT1(_L("=== Segment size: [%d Bytes]"), 1 << SegmentSizeInBytesLog2);
898 __PRINT1(_L("=== Min data size: [%d Bytes]"), iMinSizeInPages << iPageSizeLog2);
899 __PRINT1(_L("=== Max data size: [%d Bytes]"), iMaxSizeInPages << iPageSizeLog2);
902 const TUint32 pageMemSizeLog2 = iPageSizeLog2 > SegmentSizeInBytesLog2 ? iPageSizeLog2 : SegmentSizeInBytesLog2;
903 __PRINT1(_L("=== Min memory size: [%d Bytes]"), iMinSizeInPages << pageMemSizeLog2);
904 __PRINT1(_L("=== Max memory size: [%d Bytes]"), iMaxSizeInPages << pageMemSizeLog2);
907 __PRINT1(_L("=== Number of pages reserved: [%d]"), iMinSizeInPages);
908 __PRINT1(_L("=== Reserved memory: [%d Bytes]"), (iMinSizeInPages * PageSizeInSegs()) << SegmentSizeInBytesLog2);
910 __PRINT1(_L("=== Number of pages locked: [%d]"), iLockedQCount);
911 __PRINT1(_L("=== Locked memory: [%d Bytes]"), (iLockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2);
913 __PRINT1(_L("=== Number of pages unlocked: [%d]"), iUnlockedQCount);
914 __PRINT1(_L("=== Unlocked memory: [%d Bytes]"), (iUnlockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2);
918 Dump cache content, only enabled in debug mode.
919 @see CDynamicDirCache::Control()
921 void CDynamicDirCache::Dump()
923 __PRINT(_L("======== CDynamicDirCache::Dump ========="));
924 if (!iLockedQ.IsEmpty())
926 TDblQueIter<TDynamicDirCachePage> q(iLockedQ);
929 while((TDynamicDirCachePage*)q)
931 TDynamicDirCachePage* pP = q++;
932 __PRINT5(_L("=== CDynamicDirCache::iLockedQ\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes());
935 if (!iUnlockedQ.IsEmpty())
937 TDblQueIter<TDynamicDirCachePage> q(iUnlockedQ);
940 while((TDynamicDirCachePage*)q)
942 TDynamicDirCachePage* pP = q++;
943 __PRINT5(_L("=== CDynamicDirCache::iUnlockedQ\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes());
947 if (iLookupTable.Count())
950 THashSetIter<TLookupEntry> iter(iLookupTable);
951 TLookupEntry* pEntry;
952 pEntry = (TLookupEntry*) iter.Next();
955 TDynamicDirCachePage* pP = pEntry->iPage;
956 __PRINT5(_L("=== CDynamicDirCache::iLookupTable\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes());
957 pEntry = (TLookupEntry*) iter.Next();
960 __PRINT(_L("===========================================\n"));
965 Lock an unlocked page, or do nothing if the page is already locked.
966 @return TUint8* pointer of the page to be locked, if locking is successful, otherwise return NULL.
967 @param aPage the pointer of the page to be locked.
969 TUint8* CDynamicDirCache::LockPage(TDynamicDirCachePage* aPage)
971 ASSERT(aPage != NULL);
972 if (aPage->IsLocked())
973 return aPage->StartPtr();
975 TInt r = iCacheMemoryClient->LockSegments(aPage->StartPtr(), PageSizeInSegs());
978 aPage->SetLocked(ETrue);
979 return aPage->StartPtr();
986 Unlock a locked page.
987 @return TInt KErrNone if unlocking was successful, otherwise system-wide error code.
988 @param aPage the pointer of the page to be unlocked.
990 TInt CDynamicDirCache::UnlockPage(TDynamicDirCachePage* aPage)
992 ASSERT(aPage != NULL);
993 __PRINT1(_L("CDynamicDirCache::UnlockPage(%lx)"), aPage->StartPos());
994 TInt r = iCacheMemoryClient->UnlockSegments(aPage->StartPtr(), PageSizeInSegs());
997 aPage->SetLocked(EFalse);
1003 Decommit a locked or unlocked page.
1004 @return TInt KErrNone if decommition was successful, otherwise system-wide error code.
1005 @param aPage the pointer of the page to be decommitted.
1007 TInt CDynamicDirCache::DecommitPage(TDynamicDirCachePage* aPage)
1009 ASSERT(aPage != NULL);
1010 __PRINT1(_L("CDynamicDirCache::DecommitPage(%lx)"), aPage->StartPos());
1013 TInt r = iCacheMemoryClient->DecommitSegments(aPage->StartPtr(), PageSizeInSegs());
1016 aPage->SetLocked(EFalse);
1017 aPage->SetValid(EFalse);
1021 return KErrArgument;
1024 /////////////////////////// aluxiliary functions //////////////////////////////////
1026 Calculate the page size in segments. Segment size is the size of the kernel memory unit that cache memory manager manages.
1027 We are making assumption here about the page size: page size should always be either less than segment size
1028 or multiple times of segment size
1029 @return TUint32 the page size in segments.
1031 TUint32 CDynamicDirCache::PageSizeInSegs() const
1033 // initialize cache memory manager as all file systems have mounted by now
1034 ASSERT(CCacheMemoryManagerFactory::CacheMemoryManager());
1035 const TUint32 SegmentSizeInBytesLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2();
1037 // Page size should be non-zero
1038 ASSERT(iPageSizeInBytes);
1040 TUint32 segs = iPageSizeInBytes >> SegmentSizeInBytesLog2;
1041 return segs > 0 ? segs : 1;
1045 Deque the page from locked queue or unlocked queue. All pages are managed through these two queues, expect iActive
1047 @param aPage the pointer of the page to be dequeued
1048 @return TInt KErrArgument if aPage is invalid, otherwise KErrNone.
1050 TInt CDynamicDirCache::DeQueue(TDynamicDirCachePage* aPage)
1054 return KErrArgument;
1056 if (aPage->iType == TDynamicDirCachePage::ELocked)
1059 aPage->SetPageType(TDynamicDirCachePage::EUnknown);
1062 else if (aPage->iType == TDynamicDirCachePage::EUnlocked)
1065 aPage->SetPageType(TDynamicDirCachePage::EUnknown);
1071 return KErrArgument;
1077 Insert a page to the first position of locked queue or unlocked queue.
1078 @param aPage the pointer of the page to be inserted.
1079 @param aType the type of the queue to be inserted.
1080 @return TInt KErrArgument if aPage is invalid, otherwise KErrNone.
1082 TInt CDynamicDirCache::AddFirstOntoQueue(TDynamicDirCachePage* aPage, TDynamicDirCachePage::TPageType aType)
1086 return KErrArgument;
1088 if (aType == TDynamicDirCachePage::ELocked)
1090 iLockedQ.AddFirst(*aPage);
1091 aPage->SetPageType(TDynamicDirCachePage::ELocked);
1094 else if (aType == TDynamicDirCachePage::EUnlocked)
1096 iUnlockedQ.AddFirst(*aPage);
1097 aPage->SetPageType(TDynamicDirCachePage::EUnlocked);
1103 return KErrArgument;
1110 Remove a page from the lookup table, indexed by the starting media address of the page content.
1111 @param aPagePos the starting media position of the page to be removed.
1113 TInt CDynamicDirCache::LookupTblRemove(TInt64 aPagePos)
1120 TInt r = iLookupTable.Remove(TLookupEntry(aPagePos, 0, NULL));
1125 Insert a page to the lookup table, indexed by the starting media address of the page content.
1126 @param aPagePos the starting media position of the page to be inserted.
1128 TInt CDynamicDirCache::LookupTblAdd(TDynamicDirCachePage* aPage)
1132 return KErrArgument;
1134 if (aPage->StartPos() == 0)
1139 TInt r = iLookupTable.Insert(TLookupEntry(aPage->StartPos(), iPageSizeInBytes, aPage));
1144 Reset the media address of the page to 0, also invalidate the page.
1145 @param aPage the pointer of the page to be reset.
1147 TInt CDynamicDirCache::ResetPagePos(TDynamicDirCachePage* aPage)
1151 return KErrArgument;
1158 Search the lookup table to find the page start with a specific media address.
1159 @param aPos the starting media address to be searched.
1161 TDynamicDirCachePage* CDynamicDirCache::LookupTblFind(TInt64 aPos)
1169 TLookupEntry* entry = iLookupTable.Find(TLookupEntry(aPos, 0, NULL));
1172 // last entry on used queue is used as the 'active' page & may not be valid
1173 if (!entry->iPage->IsValid())
1176 return entry->iPage;