sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // f32\sfat\sl_dir_cache.cpp sl@0: // sl@0: // sl@0: sl@0: #include "sl_std.h" sl@0: #include "sl_dir_cache.h" sl@0: sl@0: //====================================================================== sl@0: TDynamicDirCachePage::~TDynamicDirCachePage() sl@0: { sl@0: } sl@0: sl@0: /** sl@0: The static cache page creation function. sl@0: Cache page objects are not supposed to be created on the stack, so this factory function is required. sl@0: */ sl@0: TDynamicDirCachePage* TDynamicDirCachePage::NewL(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr) sl@0: { sl@0: return new(ELeave) TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr); sl@0: } sl@0: sl@0: /** sl@0: Cache page constructor. sl@0: @param aOwnerCache pointer of the cache that owns this page sl@0: @param aStartMedPos the start address on the media that this page caches sl@0: @param aStartRamAddr the start address in the ram that this page content lives sl@0: */ sl@0: TDynamicDirCachePage::TDynamicDirCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr) sl@0: :iStartMedPos(aStartMedPos), sl@0: iStartRamAddr(aStartRamAddr), sl@0: iOwnerCache(aOwnerCache), sl@0: iValid(EFalse), sl@0: iLocked(EFalse) sl@0: { sl@0: //__PRINT3(_L("TDynamicDirCachePage::TDynamicDirCachePage(aStartMedPos=%lx, aStartRamAddr=0x%X, aPageSize=%u)"), aStartMedPos, aStartRamAddr, PageSizeInBytes()); sl@0: iType = EUnknown; sl@0: } sl@0: sl@0: /////////////////////////////// class CDynamicDirCache::TLookupEntry /////////////////////////// sl@0: /** sl@0: Required by RHashSet to identify individual hash set entries. sl@0: @see RHashSet sl@0: */ sl@0: TBool IdentityFunction(const TLookupEntry& aEntry1, const TLookupEntry& aEntry2) sl@0: { sl@0: // only check starting med pos for hash searching sl@0: return aEntry1.iPos == aEntry2.iPos; sl@0: } sl@0: /** sl@0: Required by RHashSet to generate hash value. sl@0: @see RHashSet sl@0: */ sl@0: TUint32 HashFunction(const TLookupEntry& aEntry) sl@0: { sl@0: return (DefaultHash::Integer(I64HIGH(aEntry.iPos)) + DefaultHash::Integer(I64LOW(aEntry.iPos))); sl@0: } sl@0: sl@0: /////////////////////////////// class CDynamicDirCache /////////////////////////// sl@0: CDynamicDirCache::~CDynamicDirCache() sl@0: { sl@0: __PRINT(_L("CDynamicDirCache::~CDynamicDirCache()")); sl@0: sl@0: // we should never decommit locked pages sl@0: while (!iLockedQ.IsEmpty()) sl@0: { sl@0: TDynamicDirCachePage* page = iLockedQ.Last(); sl@0: DeQueue(page); // remove from queue sl@0: LookupTblRemove(page->StartPos()); // remove from lookuptable sl@0: delete page; sl@0: } sl@0: ASSERT(iLockedQCount == 0); sl@0: sl@0: while (!iUnlockedQ.IsEmpty()) sl@0: { sl@0: TDynamicDirCachePage* page = iUnlockedQ.Last(); sl@0: DeQueue(page); // remove from queue sl@0: LookupTblRemove(page->StartPos()); // remove from lookuptable sl@0: DecommitPage(page); // inform cache client to decommit page memory sl@0: delete page; sl@0: } sl@0: ASSERT(iUnlockedQCount == 0); sl@0: sl@0: ASSERT(iLookupTable.Count() == 0); sl@0: iLookupTable.Close(); sl@0: if (iCacheMemoryClient) sl@0: iCacheMemoryClient->Reset(); sl@0: } sl@0: sl@0: /** sl@0: Constructor of CDynamicDirCache. sl@0: @param aDrive local drive interface to read/write media sl@0: @param aMinPageNum the minimum page number for the cache, includes iActive page and locked pages. sl@0: @param aMaxPageNum the maximum page number for the cache, includes iActive page, locked pages and unlocked pages. sl@0: @param aPageSizeInBytesLog2 the log2 value of page size in bytes, assumes page size is always a power of two sl@0: */ sl@0: CDynamicDirCache::CDynamicDirCache(TDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeInBytesLog2) sl@0: :iPageSizeLog2(aPageSizeInBytesLog2), sl@0: iMinSizeInPages(aMinPageNum), sl@0: iMaxSizeInPages(aMaxPageNum), sl@0: iDrive(aDrive), sl@0: iLockedQ(_FOFF(TDynamicDirCachePage, iLink)), sl@0: iUnlockedQ(_FOFF(TDynamicDirCachePage, iLink)), sl@0: iLockedQCount(0), sl@0: iUnlockedQCount(0), sl@0: iHashFunction(HashFunction), sl@0: iIdentityFunction(IdentityFunction), sl@0: iLookupTable(iHashFunction, iIdentityFunction) sl@0: { sl@0: iPageSizeInBytes = 1 << aPageSizeInBytesLog2; sl@0: iCacheDisabled = EFalse; sl@0: iMinCacheSizeInBytes = aMinPageNum << aPageSizeInBytesLog2; sl@0: iMaxCacheSizeInBytes = aMaxPageNum << aPageSizeInBytesLog2; sl@0: ASSERT(iPageSizeInBytes && iPageSizeInBytes <= iMinCacheSizeInBytes && iMinCacheSizeInBytes <= iMaxCacheSizeInBytes); sl@0: // initial value, will be reset from outside sl@0: iCacheBasePos = 0; sl@0: } sl@0: sl@0: /** sl@0: Second phase constructor of CDynamicDirCache. sl@0: @param aClientName the identification of cache memeory client this cache connects sl@0: */ sl@0: void CDynamicDirCache::ConstructL(const TDesC& aClientName) sl@0: { sl@0: // __PRINT3(_L("CDynamicDirCache::ConstructL(Min=%u, Max=%u, page=%u)"), iMinCacheSizeInBytes, iMaxCacheSizeInBytes, iPageSizeInBytes); sl@0: CCacheMemoryManager* manager = CCacheMemoryManagerFactory::CacheMemoryManager(); sl@0: if (manager) sl@0: { sl@0: // client will register itself onto cache memory manager when created sl@0: // note this operation may leave under OOM condition sl@0: iCacheMemoryClient = manager->ConnectClientL(aClientName, iMinSizeInPages * PageSizeInSegs(), iMaxSizeInPages * PageSizeInSegs()); sl@0: } sl@0: else sl@0: { sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: ASSERT(iCacheMemoryClient); sl@0: if (!iCacheMemoryClient) sl@0: { sl@0: User::Leave(KErrNoMemory); sl@0: } sl@0: sl@0: sl@0: // allocate as many permanently locked pages as there are threads - plus one sl@0: // otherwise DoMakePageMRU() won't work properly with only one thread sl@0: //-- At present moment the size of TDrive thread pool is 1 (1 drive thread in a pool) sl@0: iPermanentlyAllocatedPageCount = 1; sl@0: sl@0: if (iPermanentlyAllocatedPageCount > iMinSizeInPages) sl@0: iMinSizeInPages = iPermanentlyAllocatedPageCount; sl@0: sl@0: for (TUint n=0; nConstructL(aClientName); sl@0: CleanupStack::Pop(); sl@0: return pSelf; sl@0: } sl@0: sl@0: /** sl@0: Insert an unlocked page into the last position of the locked queue, may squeeze the original last page into sl@0: the unlocked queue. sl@0: This function is used on last visited but 'unlocked' pages to avoid excessive lock/unlock calls to cache memory sl@0: manager as contiguous entry reading/writing often happens on the same page. sl@0: @param aPage the page to be inserted. sl@0: @pre the page type of aPage should only be TDynamicDirCachePage::EUnknown sl@0: */ sl@0: void CDynamicDirCache::MakePageLastLocked(TDynamicDirCachePage* aPage) sl@0: { sl@0: // this function should not be called on active pages sl@0: ASSERT(aPage->iType == TDynamicDirCachePage::EUnknown); sl@0: sl@0: if (iLockedQ.IsEmpty()) sl@0: { sl@0: // if locked queue is empty, add it onto the locked queue directly sl@0: AddFirstOntoQueue(aPage, TDynamicDirCachePage::ELocked); sl@0: } sl@0: else sl@0: { sl@0: // otherwise, we squeeze for the last position on locked queue sl@0: while (iLockedQCount + 1 >= iMinSizeInPages) sl@0: { sl@0: TDynamicDirCachePage* last = iLockedQ.Last(); sl@0: DeQueue(last); sl@0: UnlockPage(last); sl@0: AddFirstOntoQueue(last, TDynamicDirCachePage::EUnlocked); sl@0: } sl@0: sl@0: // iLockedQCount + 1 < iMinSizeInPages sl@0: iLockedQ.AddLast(*aPage); sl@0: aPage->SetPageType(TDynamicDirCachePage::ELocked); sl@0: iLockedQCount++; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Read data from a single page. If the page is not found or not valid anymore, read media onto iActive page first. sl@0: The data will be _Appended_ the the descriptor aDes. The caller is responsible for maintaining this descriptor. sl@0: sl@0: @param aPos the starting position of the media address to be read. sl@0: @param aLength the length of the content to be read. sl@0: @param aDes the descriptor to contain the content. sl@0: @pre aLength should be no more than page size. sl@0: */ sl@0: void CDynamicDirCache::ReadDataFromSinglePageL(TInt64 aPos, TInt aLength, TDes8& aDes) sl@0: { sl@0: //-- the data section is in the cache page entirely, take data directly from the cache sl@0: TDynamicDirCachePage* pPage = FindPageByPos(aPos); sl@0: if (pPage) sl@0: { sl@0: // lock page before reading, sl@0: if (LockPage(pPage) != NULL) sl@0: { sl@0: // read data and append them to the descriptor sl@0: aDes.Append(pPage->PtrInPage(aPos), aLength); sl@0: sl@0: sl@0: // if page is from unlocked queue, insert it onto the last page of the locked sl@0: // queue. this is to avoid excessive locking and unlocking operations that is sl@0: // highly likely to happen for following reads. sl@0: if (pPage->PageType() == TDynamicDirCachePage::EUnlocked) sl@0: { sl@0: DeQueue(pPage); sl@0: MakePageLastLocked(pPage); sl@0: } sl@0: } sl@0: else // page locking failed sl@0: { sl@0: ASSERT(pPage->PageType() == TDynamicDirCachePage::EUnlocked); sl@0: DeQueue(pPage); sl@0: LookupTblRemove(pPage->StartPos()); sl@0: DecommitPage(pPage); sl@0: delete pPage; sl@0: pPage = NULL; sl@0: } sl@0: } sl@0: sl@0: if (!pPage) sl@0: { sl@0: // if page not found or page data not valid anymore, use active page to read data in sl@0: pPage = UpdateActivePageL(aPos); sl@0: // read data and append them to the descriptor sl@0: aDes.Append(pPage->PtrInPage(aPos), aLength); sl@0: } sl@0: sl@0: } sl@0: sl@0: //==================================================================== sl@0: /** sl@0: Implementation of pure virtual function. sl@0: @see MWTCacheInterface::ReadL() sl@0: */ sl@0: void CDynamicDirCache::ReadL(TInt64 aPos, TInt aLength, TDes8& aDes) sl@0: { sl@0: #ifdef _DEBUG sl@0: if(iCacheDisabled) sl@0: { sl@0: // cache is disabled for debug purposes sl@0: __PRINT(_L("CDynamicDirCache disabled")); sl@0: User::LeaveIfError(iDrive.ReadNonCritical(aPos, aLength, aDes)); sl@0: return; sl@0: } sl@0: #endif //_DEBUG sl@0: sl@0: aDes.Zero(); sl@0: const TUint32 PageSz = iPageSizeInBytes;//-- cache page size sl@0: sl@0: TInt64 pageStartMedPos = CalcPageStartPos(aPos); sl@0: const TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos); //-- number of bytes from aPos to the end of the page sl@0: sl@0: // __PRINT5(_L("CDynamicDirCache::ReadL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, aLength, pageStartMedPos, PageSz, bytesToPageEnd); sl@0: // if all data needed is on a single page sl@0: if((TUint32)aLength <= bytesToPageEnd) sl@0: { sl@0: ReadDataFromSinglePageL(aPos, aLength, aDes); sl@0: } sl@0: // or data to be read cross cache page boundary or probably we have more than 1 page to read sl@0: else sl@0: { sl@0: __PRINT(_L("CDynamicDirCache::ReadL() CROSS PAGE!")); sl@0: TUint32 dataLen(aLength); //-- current data length sl@0: TInt64 currMediaPos(aPos); //-- current media position sl@0: sl@0: //-- 1. read data that are already in the current page sl@0: ReadDataFromSinglePageL(currMediaPos, bytesToPageEnd, aDes); sl@0: dataLen -= bytesToPageEnd; sl@0: currMediaPos += bytesToPageEnd; sl@0: sl@0: //-- 2. read whole pages of data sl@0: while (dataLen >= PageSz) sl@0: { sl@0: //-- find out if currMediaPos is in cache. If not, find a spare page and read data there sl@0: ReadDataFromSinglePageL(currMediaPos, PageSz, aDes); sl@0: currMediaPos += PageSz; sl@0: dataLen -= PageSz; sl@0: } sl@0: sl@0: //-- 3. read the rest of the data sl@0: if(dataLen > 0) sl@0: { sl@0: ReadDataFromSinglePageL(currMediaPos, dataLen, aDes); sl@0: } sl@0: } //else((TUint32)aLength <= bytesToPageEnd) sl@0: } sl@0: sl@0: /** sl@0: Write data through a single page. If the page is not found or not valid anymore, read media onto iActive page sl@0: first, then write data through iActive page. sl@0: @param aPos the starting position of the media address to be write. sl@0: @param aData the starting address that the writing content lives in the ram. sl@0: @param aDataLen the length of the content to be written. sl@0: @pre aDataLen should be no more than page size. sl@0: */ sl@0: void CDynamicDirCache::WriteDataOntoSinglePageL(TInt64 aPos, const TUint8* aData, TUint32 aDataLen) sl@0: { sl@0: ASSERT(aDataLen <= iPageSizeInBytes); sl@0: //-- the data section is in the cache page entirely, take data directly from the cache sl@0: TDynamicDirCachePage* pPage = FindPageByPos(aPos); sl@0: if (pPage) sl@0: { sl@0: // lock page before writing, sl@0: if (LockPage(pPage) != NULL) sl@0: { sl@0: //-- update cache sl@0: Mem::Copy(pPage->PtrInPage(aPos), aData, aDataLen); sl@0: } sl@0: else sl@0: { sl@0: ASSERT(pPage->PageType() == TDynamicDirCachePage::EUnlocked); sl@0: DeQueue(pPage); sl@0: LookupTblRemove(pPage->StartPos()); sl@0: DecommitPage(pPage); sl@0: delete pPage; sl@0: pPage = NULL; sl@0: } sl@0: } sl@0: sl@0: // if page not found or page data not valid anymore, use active page to read data in sl@0: if (!pPage) sl@0: { sl@0: pPage = UpdateActivePageL(aPos); sl@0: //-- update cache sl@0: Mem::Copy(pPage->PtrInPage(aPos), aData, aDataLen); sl@0: } sl@0: sl@0: // make sure the page is unlocked after use sl@0: if (pPage->PageType() == TDynamicDirCachePage::EUnlocked) sl@0: { sl@0: UnlockPage(pPage); sl@0: } sl@0: sl@0: // always make writting events MRU sl@0: DoMakePageMRU(aPos); sl@0: return; sl@0: } sl@0: sl@0: /** sl@0: Implementation of pure virtual function. sl@0: @see MWTCacheInterface::WriteL() sl@0: */ sl@0: void CDynamicDirCache::WriteL(TInt64 aPos,const TDesC8& aDes) sl@0: { sl@0: #ifdef _DEBUG sl@0: if(iCacheDisabled) sl@0: { sl@0: // cache is disabled for debug purposes sl@0: __PRINT(_L("CDynamicDirCache disabled")); sl@0: User::LeaveIfError(iDrive.WriteCritical(aPos,aDes)); sl@0: return; sl@0: } sl@0: #endif //_DEBUG sl@0: sl@0: TUint32 dataLen = aDes.Size(); sl@0: const TUint8* pData = aDes.Ptr(); sl@0: const TUint32 PageSz = iPageSizeInBytes; //-- cache page size sl@0: sl@0: TInt64 pageStartMedPos = CalcPageStartPos(aPos); sl@0: TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos); sl@0: sl@0: // __PRINT5(_L("CDynamicDirCache::WriteL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, dataLen, pageStartMedPos, PageSz, bytesToPageEnd); sl@0: sl@0: if(dataLen <= bytesToPageEnd) sl@0: { sl@0: WriteDataOntoSinglePageL(aPos, pData, dataLen); sl@0: } sl@0: else sl@0: { sl@0: __PRINT(_L("CDynamicDirCache::WriteL() CROSS PAGE!")); sl@0: sl@0: //-- Data to be written cross cache page boundary or probably we have more than 1 page to write sl@0: TInt64 currMediaPos(aPos); sl@0: sl@0: //-- 1. update the current page sl@0: WriteDataOntoSinglePageL(currMediaPos, pData, bytesToPageEnd); sl@0: sl@0: pData += bytesToPageEnd; sl@0: currMediaPos += bytesToPageEnd; sl@0: dataLen -= bytesToPageEnd; sl@0: sl@0: //-- 2. write whole pages of data to the cache sl@0: while (dataLen >= PageSz) sl@0: { sl@0: WriteDataOntoSinglePageL(currMediaPos, pData, PageSz); sl@0: sl@0: pData += PageSz; sl@0: currMediaPos += PageSz; sl@0: dataLen -= PageSz; sl@0: } sl@0: sl@0: //-- 3. write the rest of the data sl@0: if(dataLen > 0) sl@0: { sl@0: WriteDataOntoSinglePageL(currMediaPos, pData, dataLen); sl@0: } sl@0: }// else(dataLen <= bytesToPageEnd) sl@0: sl@0: sl@0: //-- write data to the media sl@0: const TInt nErr = iDrive.WriteCritical(aPos,aDes); sl@0: if(nErr != KErrNone) sl@0: {//-- some serious problem occured during writing, invalidate cache. sl@0: InvalidateCache(); sl@0: User::Leave(nErr); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Invalidate the cache sl@0: @see MWTCacheInterface::InvalidateCache() sl@0: */ sl@0: void CDynamicDirCache::DoInvalidateCache(void) sl@0: { sl@0: __PRINT2(_L("CDynamicDirCache::InvalidateCache(locked=%d, unlocked=%d)"), iLockedQCount, iUnlockedQCount); sl@0: // we should never decommit locked pages as they needs to be reserved anyway sl@0: // the overhead of unnecessary page committing operations sl@0: sl@0: TInt pagesToRemoveFromLockedQueue = iLockedQCount - iPermanentlyAllocatedPageCount; sl@0: TInt n; sl@0: for (n=0; nStartPos()); // remove from lookuptable sl@0: DecommitPage(page); // inform cache client to decommit page memory sl@0: delete page; sl@0: } sl@0: ASSERT(iLockedQCount == iPermanentlyAllocatedPageCount); sl@0: sl@0: TDblQueIter q(iLockedQ); sl@0: q.SetToFirst(); sl@0: while((TDynamicDirCachePage*) q) sl@0: { sl@0: TDynamicDirCachePage* page = q++; sl@0: LookupTblRemove(page->StartPos());// remove from lookuptable sl@0: ResetPagePos(page); // reset start media position (0), invalidate page content sl@0: } sl@0: sl@0: // however we should decommit unlocked pages here sl@0: while (!iUnlockedQ.IsEmpty()) sl@0: { sl@0: TDynamicDirCachePage* page = iUnlockedQ.Last(); sl@0: DeQueue(page); // remove from queue sl@0: LookupTblRemove(page->StartPos()); // remove from lookuptable sl@0: DecommitPage(page); // inform cache client to decommit page memory sl@0: delete page; sl@0: } sl@0: ASSERT(iUnlockedQCount == 0); sl@0: sl@0: ASSERT(iLockedQCount == iPermanentlyAllocatedPageCount); sl@0: sl@0: ASSERT(iCacheMemoryClient); sl@0: } sl@0: sl@0: /** sl@0: Implementation of pure virtual function. sl@0: @see MWTCacheInterface::InvalidateCache() sl@0: */ sl@0: void CDynamicDirCache::InvalidateCache(void) sl@0: { sl@0: DoInvalidateCache(); sl@0: } sl@0: sl@0: /** this method isn't implemented*/ sl@0: void CDynamicDirCache::InvalidateCachePage(TUint64 /*aPos*/) sl@0: { sl@0: ASSERT(0); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Implementation of pure virtual function. sl@0: @see MWTCacheInterface::PosCached() sl@0: */ sl@0: TUint32 CDynamicDirCache::PosCached(const TInt64& aPos, TInt64& aCachedPosStart) sl@0: { sl@0: const TInt64 pageStartMedPos = CalcPageStartPos(aPos); sl@0: sl@0: // only search the page in lookup table sl@0: // NOTE: we don't count the active page into acount here, sl@0: // this is to avoid pulling next pages recursively sl@0: TDynamicDirCachePage* pPage = LookupTblFind(pageStartMedPos); sl@0: sl@0: // then check if page is still valid if page is on Unlocked Page Queue sl@0: if (pPage && pPage->PageType() == TDynamicDirCachePage::EUnlocked) sl@0: { sl@0: if (LockPage(pPage) != NULL) sl@0: { sl@0: // __PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) found on Unlocked Queue!"), aPos); sl@0: // have to unlock it before returning, otherwise there will be memory leak sl@0: UnlockPage(pPage); sl@0: aCachedPosStart = pPage->StartPos(); sl@0: return pPage->PageSizeInBytes(); sl@0: } sl@0: else // if the unlocked page is not valid anymore, remove it sl@0: { sl@0: DeQueue(pPage); sl@0: LookupTblRemove(pPage->StartPos()); sl@0: DecommitPage(pPage); sl@0: delete pPage; sl@0: pPage = NULL; sl@0: } sl@0: } sl@0: // otherwise if page is already locked or valid active page sl@0: else if (pPage) sl@0: { sl@0: __PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) on Locked Queue!"), aPos); sl@0: aCachedPosStart = pPage->StartPos(); sl@0: return pPage->PageSizeInBytes(); sl@0: } sl@0: sl@0: // page is not found or not valid anymore sl@0: return 0; sl@0: } sl@0: sl@0: /** sl@0: Implementation of pure virtual function. sl@0: @see MWTCacheInterface::CacheSizeInBytes() sl@0: */ sl@0: TUint32 CDynamicDirCache::CacheSizeInBytes() const sl@0: { sl@0: return iMaxCacheSizeInBytes; sl@0: } sl@0: sl@0: /** sl@0: Implementation of pure virtual function. sl@0: @see MWTCacheInterface::Control() sl@0: */ sl@0: TInt CDynamicDirCache::Control(TUint32 aFunction, TUint32 aParam1, TAny* aParam2) sl@0: { sl@0: TInt r = KErrNotSupported; sl@0: #ifdef _DEBUG sl@0: (void)aParam2; sl@0: switch(aFunction) sl@0: { sl@0: // disable / enable cache, for debug sl@0: // if aParam1 != 0 cache will be disabled, enabled otherwise sl@0: case EDisableCache: sl@0: iCacheDisabled = aParam1 ? 1 : 0; sl@0: r = KErrNone; sl@0: break; sl@0: sl@0: // dump cache, for debug sl@0: case EDumpCache: sl@0: { sl@0: RFs fs; sl@0: fs.Connect(); sl@0: const TUint32 debugRegister = DebugRegister(); sl@0: fs.SetDebugRegister(debugRegister|KFSYS); sl@0: Dump(); sl@0: fs.SetDebugRegister(debugRegister); sl@0: fs.Close(); sl@0: break; sl@0: } sl@0: case ECacheInfo: sl@0: { sl@0: RFs fs; sl@0: fs.Connect(); sl@0: const TUint32 debugRegister = DebugRegister(); sl@0: fs.SetDebugRegister(debugRegister|KFSYS); sl@0: Info(); sl@0: fs.SetDebugRegister(debugRegister); sl@0: fs.Close(); sl@0: break; sl@0: } sl@0: sl@0: default: sl@0: __PRINT1(_L("CDynamicDirCache::Control() invalid function: %d"), aFunction); sl@0: ASSERT(0); sl@0: break; sl@0: } sl@0: sl@0: #else sl@0: (void)aFunction; //-- supress warnings sl@0: (void)aParam1; sl@0: (void)aParam2; sl@0: User::Invariant(); //-- don't call this method in release build sl@0: #endif //_DEBUG sl@0: sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Implementation of pure virtual function. sl@0: @see MWTCacheInterface::SetCacheBasePos() sl@0: */ sl@0: void CDynamicDirCache::SetCacheBasePos(TInt64 aBasePos) sl@0: { sl@0: iCacheBasePos = aBasePos; sl@0: } sl@0: sl@0: /** sl@0: Implementation of pure virtual function. sl@0: @see MWTCacheInterface::SetCacheBasePos() sl@0: */ sl@0: TUint32 CDynamicDirCache::PageSizeInBytesLog2() const sl@0: { sl@0: return iPageSizeLog2; sl@0: } sl@0: sl@0: sl@0: void CDynamicDirCache::DoMakePageMRU(TInt64 aPos) sl@0: { sl@0: // __PRINT1(_L("MakePageMRU (%lx)"), aPos); sl@0: // __PRINT4(_L("Current Cache State: iLockedQCount=%d, iUnlockedQCount=%d, iLookupTbl=%d, iMaxSizeInPages=%d"), iLockedQCount, iUnlockedQCount, iLookupTable.Count(), iMaxSizeInPages); sl@0: // check the MRU page first, if it is already the MRU page, we can return immediately sl@0: TInt64 pageStartMedPos = CalcPageStartPos(aPos); sl@0: if (!iLockedQ.IsEmpty()) sl@0: { sl@0: if (iLockedQ.First()->StartPos() == pageStartMedPos) sl@0: { sl@0: return; sl@0: } sl@0: } sl@0: sl@0: TDynamicDirCachePage* pPage = FindPageByPos(aPos); sl@0: if (pPage) sl@0: { sl@0: ASSERT(pPage->IsValid()); sl@0: // lock page before make it MRU sl@0: if (pPage->PageType() == TDynamicDirCachePage::EUnlocked) sl@0: { sl@0: ASSERT(!pPage->IsLocked()); sl@0: if (LockPage(pPage) == NULL) sl@0: { sl@0: DeQueue(pPage); sl@0: LookupTblRemove(pPage->StartPos()); sl@0: DecommitPage(pPage); sl@0: delete pPage; sl@0: pPage = NULL; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // error checking: page should either be locked or active sl@0: ASSERT(LockPage(pPage) != NULL); sl@0: } sl@0: } sl@0: sl@0: // if page not found or page data not valid anymore, use active page to read data sl@0: if (!pPage) sl@0: { sl@0: TRAPD(err, pPage = UpdateActivePageL(aPos)); sl@0: if (err != KErrNone) sl@0: { sl@0: // problem occurred reading active page, return immediately. sl@0: return; sl@0: } sl@0: } sl@0: sl@0: // by now, the page is either locked or active page sl@0: ASSERT(pPage && pPage->IsValid() && pPage->IsLocked()); sl@0: sl@0: sl@0: sl@0: TBool allocateNewPage = pPage == iLockedQ.Last() && !CacheIsFull(); sl@0: sl@0: sl@0: switch (pPage->PageType()) sl@0: { sl@0: case TDynamicDirCachePage::EUnlocked: sl@0: { sl@0: // if page was originally on Unlocked Page Queque, remove it from Unlocked Page Queue, add it sl@0: // to the Locked Page Queue and make it MRU sl@0: DeQueue(pPage); sl@0: AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked); sl@0: // check cache limit sl@0: CheckThresholds(); sl@0: } sl@0: case TDynamicDirCachePage::ELocked: sl@0: { sl@0: // otherwise the page was on Locked Page Queue, make it MRU sl@0: // no need to check cache limit sl@0: if (pPage != iLockedQ.First()) sl@0: { sl@0: DeQueue(pPage); sl@0: AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked); sl@0: } sl@0: break; sl@0: } sl@0: default: sl@0: ASSERT(0); sl@0: } sl@0: sl@0: if (allocateNewPage) sl@0: { sl@0: TDynamicDirCachePage* nPage = NULL; sl@0: TRAPD(err, nPage = AllocateAndLockNewPageL(0)); sl@0: if (err == KErrNone) sl@0: { sl@0: sl@0: // about to add a page to end of locked queue, so lie about iLockedQCount sl@0: iLockedQCount++; sl@0: CheckThresholds(); sl@0: iLockedQCount--; sl@0: sl@0: iLockedQ.AddLast(*nPage); sl@0: nPage->SetPageType(TDynamicDirCachePage::ELocked); sl@0: ++iLockedQCount; sl@0: LookupTblAdd(nPage); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Implementation of pure virtual function. sl@0: @see MDiskSpecialAccessor::MakePageMRU() sl@0: */ sl@0: void CDynamicDirCache::MakePageMRU(TInt64 aPos) sl@0: { sl@0: DoMakePageMRU(aPos); sl@0: } sl@0: sl@0: //==================================================================== sl@0: /** sl@0: Internal query function, to check if aPos is cached or not. iActive page is included in searching. sl@0: */ sl@0: TDynamicDirCachePage* CDynamicDirCache::FindPageByPos(TInt64 aPos) sl@0: { sl@0: // __PRINT1(_L("CDynamicDirCache::FindPageByPos(aPos=%lx)"), aPos); sl@0: // align the page position sl@0: TInt64 pageStartMedPos = CalcPageStartPos(aPos); sl@0: sl@0: // search in lookup table sl@0: return LookupTblFind(pageStartMedPos); sl@0: } sl@0: sl@0: /** sl@0: read a page length data into iActive page and return iActive page if read is successful. sl@0: */ sl@0: TDynamicDirCachePage* CDynamicDirCache::UpdateActivePageL(TInt64 aPos) sl@0: { sl@0: // align the page position sl@0: TInt64 pageStartMedPos = CalcPageStartPos(aPos); sl@0: sl@0: ASSERT(!iLockedQ.IsEmpty()); sl@0: TDynamicDirCachePage* activePage = iLockedQ.Last(); sl@0: sl@0: if (activePage->StartPos() == pageStartMedPos && activePage->IsValid()) sl@0: { sl@0: return activePage; sl@0: } sl@0: sl@0: __PRINT2(_L("CDynamicDirCache::UpdateActivePageL(aPos=%lx, active=%lx)"), aPos, activePage->StartPos()); sl@0: sl@0: activePage->Deque(); sl@0: LookupTblRemove(activePage->StartPos()); sl@0: sl@0: // set start med pos value, no other effects, only available to active page sl@0: activePage->SetPos(pageStartMedPos); sl@0: sl@0: // read data, make active page valid sl@0: TUint8* data = activePage->PtrInPage(activePage->iStartMedPos); sl@0: TPtr8 dataPtr(data, iPageSizeInBytes); sl@0: sl@0: const TInt nErr = iDrive.ReadNonCritical(activePage->iStartMedPos, iPageSizeInBytes, dataPtr); sl@0: sl@0: iLockedQ.AddLast(*activePage); sl@0: LookupTblAdd(activePage); sl@0: sl@0: if(nErr !=KErrNone) sl@0: { sl@0: // some serious problem occured during reading, invalidate cache. sl@0: DoInvalidateCache(); sl@0: User::Leave(nErr); sl@0: } sl@0: activePage->SetValid(ETrue); sl@0: sl@0: return activePage; sl@0: } sl@0: sl@0: /** sl@0: Check if the number of (locked pages + iActive page) and unlocked pages have exceeded minimum allowed page sl@0: number and maximum allowed page number respectively. sl@0: */ sl@0: void CDynamicDirCache::CheckThresholds() sl@0: { sl@0: while (iLockedQCount + 1 > iMinSizeInPages) sl@0: { sl@0: TDynamicDirCachePage* movePage = iLockedQ.Last(); sl@0: UnlockPage(movePage); sl@0: DeQueue(movePage); sl@0: TInt err = LookupTblRemove(movePage->StartPos()); sl@0: ASSERT(err == KErrNone); sl@0: sl@0: // if it is a valid page, add onto unlocked queue sl@0: if (movePage->StartPos() != 0) sl@0: { sl@0: ASSERT(movePage->IsValid()); sl@0: AddFirstOntoQueue(movePage, TDynamicDirCachePage::EUnlocked); sl@0: err = LookupTblAdd(movePage); sl@0: ASSERT(err == KErrNone); sl@0: } sl@0: else // reserved page, delete sl@0: { sl@0: DecommitPage(movePage); sl@0: delete movePage; sl@0: } sl@0: } sl@0: sl@0: // if unlocked queue exceeds limit, delete LRU page sl@0: // note: all pages on unlocked queue should be valid sl@0: while (iUnlockedQCount > iMaxSizeInPages - iMinSizeInPages) sl@0: { sl@0: TDynamicDirCachePage* removePage = iUnlockedQ.Last(); sl@0: ASSERT(removePage->StartPos() != 0 && removePage->IsValid()); sl@0: DeQueue(removePage); sl@0: LookupTblRemove(removePage->StartPos()); sl@0: DecommitPage(removePage); sl@0: delete removePage; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Try to create a new page and lock the page content when it is created. This function should only be called sl@0: when creating iActive page or making a page MRU (which might result in page evictions). sl@0: @return the pointer of the newly created page, or NULL if allocation failed. sl@0: @param aStartMedPos the starting media address of the page to be created. sl@0: @pre aStartMedPos should not already be existing in the cache. sl@0: */ sl@0: TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPageL(TInt64 aStartMedPos) sl@0: { sl@0: __PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPageL(aStartMedPos=%lx)"), aStartMedPos); sl@0: sl@0: TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs()); sl@0: if (startRamAddr) sl@0: { sl@0: // create new page and return sl@0: TDynamicDirCachePage* pPage = TDynamicDirCachePage::NewL(this, aStartMedPos, startRamAddr); sl@0: pPage->SetLocked(ETrue); sl@0: pPage->SetValid(EFalse); sl@0: return pPage; sl@0: } sl@0: sl@0: return NULL; sl@0: } sl@0: sl@0: #ifdef _DEBUG sl@0: /** sl@0: Dump cache information, only enabled in debug mode. sl@0: @see CDynamicDirCache::Control() sl@0: */ sl@0: void CDynamicDirCache::Info() const sl@0: { sl@0: __PRINT(_L("======== CDynamicDirCache::Info =========")); sl@0: const TUint32 SegmentSizeInBytesLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2(); sl@0: // page size sl@0: __PRINT1(_L("=== Pages size: [%d Bytes]"), iPageSizeInBytes); sl@0: __PRINT1(_L("=== Segment size: [%d Bytes]"), 1 << SegmentSizeInBytesLog2); sl@0: sl@0: // data size: sl@0: __PRINT1(_L("=== Min data size: [%d Bytes]"), iMinSizeInPages << iPageSizeLog2); sl@0: __PRINT1(_L("=== Max data size: [%d Bytes]"), iMaxSizeInPages << iPageSizeLog2); sl@0: sl@0: // memory size: sl@0: const TUint32 pageMemSizeLog2 = iPageSizeLog2 > SegmentSizeInBytesLog2 ? iPageSizeLog2 : SegmentSizeInBytesLog2; sl@0: __PRINT1(_L("=== Min memory size: [%d Bytes]"), iMinSizeInPages << pageMemSizeLog2); sl@0: __PRINT1(_L("=== Max memory size: [%d Bytes]"), iMaxSizeInPages << pageMemSizeLog2); sl@0: sl@0: // reserved pages sl@0: __PRINT1(_L("=== Number of pages reserved: [%d]"), iMinSizeInPages); sl@0: __PRINT1(_L("=== Reserved memory: [%d Bytes]"), (iMinSizeInPages * PageSizeInSegs()) << SegmentSizeInBytesLog2); sl@0: // locked page num sl@0: __PRINT1(_L("=== Number of pages locked: [%d]"), iLockedQCount); sl@0: __PRINT1(_L("=== Locked memory: [%d Bytes]"), (iLockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2); sl@0: // unlocked page num sl@0: __PRINT1(_L("=== Number of pages unlocked: [%d]"), iUnlockedQCount); sl@0: __PRINT1(_L("=== Unlocked memory: [%d Bytes]"), (iUnlockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2); sl@0: } sl@0: sl@0: /** sl@0: Dump cache content, only enabled in debug mode. sl@0: @see CDynamicDirCache::Control() sl@0: */ sl@0: void CDynamicDirCache::Dump() sl@0: { sl@0: __PRINT(_L("======== CDynamicDirCache::Dump =========")); sl@0: if (!iLockedQ.IsEmpty()) sl@0: { sl@0: TDblQueIter q(iLockedQ); sl@0: q.SetToFirst(); sl@0: TInt i = 0; sl@0: while((TDynamicDirCachePage*)q) sl@0: { sl@0: TDynamicDirCachePage* pP = q++; sl@0: __PRINT5(_L("=== CDynamicDirCache::iLockedQ\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes()); sl@0: } sl@0: } sl@0: if (!iUnlockedQ.IsEmpty()) sl@0: { sl@0: TDblQueIter q(iUnlockedQ); sl@0: q.SetToFirst(); sl@0: TInt i = 0; sl@0: while((TDynamicDirCachePage*)q) sl@0: { sl@0: TDynamicDirCachePage* pP = q++; sl@0: __PRINT5(_L("=== CDynamicDirCache::iUnlockedQ\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes()); sl@0: } sl@0: } sl@0: sl@0: if (iLookupTable.Count()) sl@0: { sl@0: TInt i = 0; sl@0: THashSetIter iter(iLookupTable); sl@0: TLookupEntry* pEntry; sl@0: pEntry = (TLookupEntry*) iter.Next(); sl@0: while(pEntry) sl@0: { sl@0: TDynamicDirCachePage* pP = pEntry->iPage; sl@0: __PRINT5(_L("=== CDynamicDirCache::iLookupTable\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes()); sl@0: pEntry = (TLookupEntry*) iter.Next(); sl@0: }; sl@0: } sl@0: __PRINT(_L("===========================================\n")); sl@0: } sl@0: #endif //_DEBUG sl@0: sl@0: /** sl@0: Lock an unlocked page, or do nothing if the page is already locked. sl@0: @return TUint8* pointer of the page to be locked, if locking is successful, otherwise return NULL. sl@0: @param aPage the pointer of the page to be locked. sl@0: */ sl@0: TUint8* CDynamicDirCache::LockPage(TDynamicDirCachePage* aPage) sl@0: { sl@0: ASSERT(aPage != NULL); sl@0: if (aPage->IsLocked()) sl@0: return aPage->StartPtr(); sl@0: sl@0: TInt r = iCacheMemoryClient->LockSegments(aPage->StartPtr(), PageSizeInSegs()); sl@0: if (r == KErrNone) sl@0: { sl@0: aPage->SetLocked(ETrue); sl@0: return aPage->StartPtr(); sl@0: } sl@0: sl@0: return NULL; sl@0: } sl@0: sl@0: /** sl@0: Unlock a locked page. sl@0: @return TInt KErrNone if unlocking was successful, otherwise system-wide error code. sl@0: @param aPage the pointer of the page to be unlocked. sl@0: */ sl@0: TInt CDynamicDirCache::UnlockPage(TDynamicDirCachePage* aPage) sl@0: { sl@0: ASSERT(aPage != NULL); sl@0: __PRINT1(_L("CDynamicDirCache::UnlockPage(%lx)"), aPage->StartPos()); sl@0: TInt r = iCacheMemoryClient->UnlockSegments(aPage->StartPtr(), PageSizeInSegs()); sl@0: if (r == KErrNone) sl@0: { sl@0: aPage->SetLocked(EFalse); sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Decommit a locked or unlocked page. sl@0: @return TInt KErrNone if decommition was successful, otherwise system-wide error code. sl@0: @param aPage the pointer of the page to be decommitted. sl@0: */ sl@0: TInt CDynamicDirCache::DecommitPage(TDynamicDirCachePage* aPage) sl@0: { sl@0: ASSERT(aPage != NULL); sl@0: __PRINT1(_L("CDynamicDirCache::DecommitPage(%lx)"), aPage->StartPos()); sl@0: if (aPage) sl@0: { sl@0: TInt r = iCacheMemoryClient->DecommitSegments(aPage->StartPtr(), PageSizeInSegs()); sl@0: if (r == KErrNone) sl@0: { sl@0: aPage->SetLocked(EFalse); sl@0: aPage->SetValid(EFalse); sl@0: } sl@0: return r; sl@0: } sl@0: return KErrArgument; sl@0: } sl@0: sl@0: /////////////////////////// aluxiliary functions ////////////////////////////////// sl@0: /** sl@0: Calculate the page size in segments. Segment size is the size of the kernel memory unit that cache memory manager manages. sl@0: We are making assumption here about the page size: page size should always be either less than segment size sl@0: or multiple times of segment size sl@0: @return TUint32 the page size in segments. sl@0: */ sl@0: TUint32 CDynamicDirCache::PageSizeInSegs() const sl@0: { sl@0: // initialize cache memory manager as all file systems have mounted by now sl@0: ASSERT(CCacheMemoryManagerFactory::CacheMemoryManager()); sl@0: const TUint32 SegmentSizeInBytesLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2(); sl@0: sl@0: // Page size should be non-zero sl@0: ASSERT(iPageSizeInBytes); sl@0: sl@0: TUint32 segs = iPageSizeInBytes >> SegmentSizeInBytesLog2; sl@0: return segs > 0 ? segs : 1; sl@0: } sl@0: sl@0: /** sl@0: Deque the page from locked queue or unlocked queue. All pages are managed through these two queues, expect iActive sl@0: page. sl@0: @param aPage the pointer of the page to be dequeued sl@0: @return TInt KErrArgument if aPage is invalid, otherwise KErrNone. sl@0: */ sl@0: TInt CDynamicDirCache::DeQueue(TDynamicDirCachePage* aPage) sl@0: { sl@0: ASSERT(aPage); sl@0: if (!aPage) sl@0: return KErrArgument; sl@0: sl@0: if (aPage->iType == TDynamicDirCachePage::ELocked) sl@0: { sl@0: aPage->Deque(); sl@0: aPage->SetPageType(TDynamicDirCachePage::EUnknown); sl@0: --iLockedQCount; sl@0: } sl@0: else if (aPage->iType == TDynamicDirCachePage::EUnlocked) sl@0: { sl@0: aPage->Deque(); sl@0: aPage->SetPageType(TDynamicDirCachePage::EUnknown); sl@0: --iUnlockedQCount; sl@0: } sl@0: else sl@0: { sl@0: ASSERT(0); sl@0: return KErrArgument; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Insert a page to the first position of locked queue or unlocked queue. sl@0: @param aPage the pointer of the page to be inserted. sl@0: @param aType the type of the queue to be inserted. sl@0: @return TInt KErrArgument if aPage is invalid, otherwise KErrNone. sl@0: */ sl@0: TInt CDynamicDirCache::AddFirstOntoQueue(TDynamicDirCachePage* aPage, TDynamicDirCachePage::TPageType aType) sl@0: { sl@0: ASSERT(aPage); sl@0: if (!aPage) sl@0: return KErrArgument; sl@0: sl@0: if (aType == TDynamicDirCachePage::ELocked) sl@0: { sl@0: iLockedQ.AddFirst(*aPage); sl@0: aPage->SetPageType(TDynamicDirCachePage::ELocked); sl@0: ++iLockedQCount; sl@0: } sl@0: else if (aType == TDynamicDirCachePage::EUnlocked) sl@0: { sl@0: iUnlockedQ.AddFirst(*aPage); sl@0: aPage->SetPageType(TDynamicDirCachePage::EUnlocked); sl@0: ++iUnlockedQCount; sl@0: } sl@0: else sl@0: { sl@0: ASSERT(0); sl@0: return KErrArgument; sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Remove a page from the lookup table, indexed by the starting media address of the page content. sl@0: @param aPagePos the starting media position of the page to be removed. sl@0: */ sl@0: TInt CDynamicDirCache::LookupTblRemove(TInt64 aPagePos) sl@0: { sl@0: if (aPagePos == 0) sl@0: { sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt r = iLookupTable.Remove(TLookupEntry(aPagePos, 0, NULL)); sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Insert a page to the lookup table, indexed by the starting media address of the page content. sl@0: @param aPagePos the starting media position of the page to be inserted. sl@0: */ sl@0: TInt CDynamicDirCache::LookupTblAdd(TDynamicDirCachePage* aPage) sl@0: { sl@0: ASSERT(aPage); sl@0: if (!aPage) sl@0: return KErrArgument; sl@0: sl@0: if (aPage->StartPos() == 0) sl@0: { sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt r = iLookupTable.Insert(TLookupEntry(aPage->StartPos(), iPageSizeInBytes, aPage)); sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Reset the media address of the page to 0, also invalidate the page. sl@0: @param aPage the pointer of the page to be reset. sl@0: */ sl@0: TInt CDynamicDirCache::ResetPagePos(TDynamicDirCachePage* aPage) sl@0: { sl@0: ASSERT(aPage); sl@0: if (!aPage) sl@0: return KErrArgument; sl@0: sl@0: aPage->ResetPos(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Search the lookup table to find the page start with a specific media address. sl@0: @param aPos the starting media address to be searched. sl@0: */ sl@0: TDynamicDirCachePage* CDynamicDirCache::LookupTblFind(TInt64 aPos) sl@0: { sl@0: if (aPos == 0) sl@0: { sl@0: ASSERT(0); sl@0: return NULL; sl@0: } sl@0: sl@0: TLookupEntry* entry = iLookupTable.Find(TLookupEntry(aPos, 0, NULL)); sl@0: if(entry) sl@0: { sl@0: // last entry on used queue is used as the 'active' page & may not be valid sl@0: if (!entry->iPage->IsValid()) sl@0: return NULL; sl@0: sl@0: return entry->iPage; sl@0: } sl@0: sl@0: return NULL; sl@0: }