os/kernelhwsrv/userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,1180 @@
     1.4 +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
     1.5 +// All rights reserved.
     1.6 +// This component and the accompanying materials are made available
     1.7 +// under the terms of the License "Eclipse Public License v1.0"
     1.8 +// which accompanies this distribution, and is available
     1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.10 +//
    1.11 +// Initial Contributors:
    1.12 +// Nokia Corporation - initial contribution.
    1.13 +//
    1.14 +// Contributors:
    1.15 +//
    1.16 +// Description:
    1.17 +// f32\sfat\sl_dir_cache.cpp
    1.18 +//
    1.19 +//
    1.20 +
    1.21 +#include "sl_std.h"
    1.22 +#include "sl_dir_cache.h"
    1.23 +
    1.24 +//======================================================================
    1.25 +TDynamicDirCachePage::~TDynamicDirCachePage()
    1.26 +	{
    1.27 +	}
    1.28 +
    1.29 +/**
    1.30 +The static cache page creation function.
    1.31 +Cache page objects are not supposed to be created on the stack, so this factory function is required.
    1.32 +*/
    1.33 +TDynamicDirCachePage* TDynamicDirCachePage::NewL(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
    1.34 +	{
    1.35 +	return new(ELeave) TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr);
    1.36 +	}
    1.37 +
    1.38 +/**
    1.39 +Cache page constructor.
    1.40 +@param	aOwnerCache	pointer of the cache that owns this page
    1.41 +@param	aStartMedPos	the start address on the media that this page caches
    1.42 +@param	aStartRamAddr	the start address in the ram that this page content lives
    1.43 +*/
    1.44 +TDynamicDirCachePage::TDynamicDirCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
    1.45 +:iStartMedPos(aStartMedPos),
    1.46 +iStartRamAddr(aStartRamAddr),
    1.47 +iOwnerCache(aOwnerCache),
    1.48 +iValid(EFalse),
    1.49 +iLocked(EFalse)
    1.50 +	{
    1.51 +	//__PRINT3(_L("TDynamicDirCachePage::TDynamicDirCachePage(aStartMedPos=%lx, aStartRamAddr=0x%X, aPageSize=%u)"), aStartMedPos, aStartRamAddr, PageSizeInBytes());
    1.52 +	iType = EUnknown;
    1.53 +	}
    1.54 +
    1.55 +/////////////////////////////// class CDynamicDirCache::TLookupEntry ///////////////////////////
    1.56 +/**
    1.57 +Required by RHashSet<TLookupEntry> to identify individual hash set entries.
    1.58 +@see	RHashSet
    1.59 +*/
    1.60 +TBool IdentityFunction(const TLookupEntry& aEntry1, const TLookupEntry& aEntry2)
    1.61 +	{
    1.62 +	// only check starting med pos for hash searching
    1.63 +	return aEntry1.iPos == aEntry2.iPos;
    1.64 +	}
    1.65 +/**
    1.66 +Required by RHashSet<TLookupEntry> to generate hash value.
    1.67 +@see	RHashSet
    1.68 +*/
    1.69 +TUint32 HashFunction(const TLookupEntry& aEntry)
    1.70 +	{
    1.71 +	return (DefaultHash::Integer(I64HIGH(aEntry.iPos)) + DefaultHash::Integer(I64LOW(aEntry.iPos)));
    1.72 +	}
    1.73 +
    1.74 +/////////////////////////////// class CDynamicDirCache ///////////////////////////
    1.75 +CDynamicDirCache::~CDynamicDirCache()
    1.76 +	{
    1.77 +	__PRINT(_L("CDynamicDirCache::~CDynamicDirCache()"));
    1.78 +
    1.79 +	// we should never decommit locked pages
    1.80 +    while (!iLockedQ.IsEmpty())
    1.81 +		{
    1.82 +		TDynamicDirCachePage* page = iLockedQ.Last();
    1.83 +		DeQueue(page);		// remove from queue
    1.84 +		LookupTblRemove(page->StartPos());	// remove from lookuptable
    1.85 +		delete page;
    1.86 +		}
    1.87 +	ASSERT(iLockedQCount == 0);
    1.88 +
    1.89 +	while (!iUnlockedQ.IsEmpty())
    1.90 +		{
    1.91 +		TDynamicDirCachePage* page = iUnlockedQ.Last();
    1.92 +		DeQueue(page);		// remove from queue
    1.93 +		LookupTblRemove(page->StartPos());	// remove from lookuptable
    1.94 +		DecommitPage(page);	// inform cache client to decommit page memory
    1.95 +		delete page;
    1.96 +		}
    1.97 +	ASSERT(iUnlockedQCount == 0);
    1.98 +
    1.99 +	ASSERT(iLookupTable.Count() == 0);
   1.100 +	iLookupTable.Close();
   1.101 +    if (iCacheMemoryClient)
   1.102 +    	iCacheMemoryClient->Reset();
   1.103 +	}
   1.104 +
   1.105 +/**
   1.106 +Constructor of CDynamicDirCache.
   1.107 +@param	aDrive	local drive interface to read/write media
   1.108 +@param	aMinPageNum	the minimum page number for the cache, includes iActive page and locked pages.
   1.109 +@param	aMaxPageNum	the maximum page number for the cache, includes iActive page, locked pages and unlocked pages.
   1.110 +@param	aPageSizeInBytesLog2	the log2 value of page size in bytes, assumes page size is always a power of two
   1.111 +*/
   1.112 +CDynamicDirCache::CDynamicDirCache(TDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeInBytesLog2)
   1.113 +:iPageSizeLog2(aPageSizeInBytesLog2),
   1.114 +iMinSizeInPages(aMinPageNum),
   1.115 +iMaxSizeInPages(aMaxPageNum),
   1.116 +iDrive(aDrive),
   1.117 +iLockedQ(_FOFF(TDynamicDirCachePage, iLink)),
   1.118 +iUnlockedQ(_FOFF(TDynamicDirCachePage, iLink)),
   1.119 +iLockedQCount(0),
   1.120 +iUnlockedQCount(0),
   1.121 +iHashFunction(HashFunction),
   1.122 +iIdentityFunction(IdentityFunction),
   1.123 +iLookupTable(iHashFunction, iIdentityFunction)
   1.124 +	{
   1.125 +	iPageSizeInBytes = 1 << aPageSizeInBytesLog2;
   1.126 +	iCacheDisabled = EFalse;
   1.127 +    iMinCacheSizeInBytes = aMinPageNum << aPageSizeInBytesLog2;
   1.128 +    iMaxCacheSizeInBytes = aMaxPageNum << aPageSizeInBytesLog2;
   1.129 +    ASSERT(iPageSizeInBytes && iPageSizeInBytes <= iMinCacheSizeInBytes && iMinCacheSizeInBytes <= iMaxCacheSizeInBytes);
   1.130 +	// initial value, will be reset from outside
   1.131 +	iCacheBasePos = 0;
   1.132 +	}
   1.133 +
   1.134 +/**
   1.135 +Second phase constructor of CDynamicDirCache.
   1.136 +@param	aClientName the identification of cache memeory client this cache connects
   1.137 +*/
   1.138 +void CDynamicDirCache::ConstructL(const TDesC& aClientName)
   1.139 +	{
   1.140 +//    __PRINT3(_L("CDynamicDirCache::ConstructL(Min=%u, Max=%u, page=%u)"), iMinCacheSizeInBytes, iMaxCacheSizeInBytes, iPageSizeInBytes);
   1.141 +	CCacheMemoryManager* manager = CCacheMemoryManagerFactory::CacheMemoryManager();
   1.142 +	if (manager)
   1.143 +		{
   1.144 +		// client will register itself onto cache memory manager when created
   1.145 +		// note this operation may leave under OOM condition
   1.146 +		iCacheMemoryClient = manager->ConnectClientL(aClientName, iMinSizeInPages * PageSizeInSegs(), iMaxSizeInPages * PageSizeInSegs());
   1.147 +		}
   1.148 +	else
   1.149 +		{
   1.150 +		User::Leave(KErrNotSupported);
   1.151 +		}
   1.152 +
   1.153 +	ASSERT(iCacheMemoryClient);
   1.154 +	if (!iCacheMemoryClient)
   1.155 +		{
   1.156 +		User::Leave(KErrNoMemory);
   1.157 +		}
   1.158 +
   1.159 +
   1.160 +	// allocate as many permanently locked pages as there are threads - plus one
   1.161 +	// otherwise DoMakePageMRU() won't work properly with only one thread
   1.162 +    //-- At present moment the size of TDrive thread pool is 1 (1 drive thread in a pool)
   1.163 +	iPermanentlyAllocatedPageCount = 1; 
   1.164 +
   1.165 +	if (iPermanentlyAllocatedPageCount > iMinSizeInPages)
   1.166 +		iMinSizeInPages = iPermanentlyAllocatedPageCount;
   1.167 +
   1.168 +	for (TUint n=0; n<iPermanentlyAllocatedPageCount; n++)
   1.169 +		{
   1.170 +		TDynamicDirCachePage* pPage = AllocateAndLockNewPageL(0);
   1.171 +		AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
   1.172 +		LookupTblAdd(pPage);
   1.173 +		}
   1.174 +
   1.175 +	}
   1.176 +
   1.177 +/**
   1.178 +Static factory function of CDynamicDirCache
   1.179 +*/
   1.180 +CDynamicDirCache* CDynamicDirCache::NewL(TDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeLog2, const TDesC& aClientName)
   1.181 +    {
   1.182 +    __PRINT3(_L("CDynamicDirCache::NewL(MinPageNum=%u, MaxPageNum=%u, page=%u)"), aMinPageNum, aMaxPageNum, 1<<aPageSizeLog2);
   1.183 +    CDynamicDirCache* pSelf = new (ELeave) CDynamicDirCache(aDrive, aMinPageNum, aMaxPageNum, aPageSizeLog2);
   1.184 +    CleanupStack::PushL(pSelf);
   1.185 +    pSelf->ConstructL(aClientName);
   1.186 +    CleanupStack::Pop();
   1.187 +    return pSelf;
   1.188 +    }
   1.189 +
   1.190 +/**
   1.191 +Insert an unlocked page into the last position of the locked queue, may squeeze the original last page into
   1.192 +the unlocked queue.
   1.193 +This function is used on last visited but 'unlocked' pages to avoid excessive lock/unlock calls to cache memory
   1.194 +manager as contiguous entry reading/writing often happens on the same page.
   1.195 +@param	aPage	the page to be inserted.
   1.196 +@pre	the page type of aPage should only be TDynamicDirCachePage::EUnknown
   1.197 +*/
   1.198 +void CDynamicDirCache::MakePageLastLocked(TDynamicDirCachePage* aPage)
   1.199 +	{
   1.200 +	// this function should not be called on active pages
   1.201 +	ASSERT(aPage->iType == TDynamicDirCachePage::EUnknown);
   1.202 +
   1.203 +	if (iLockedQ.IsEmpty())
   1.204 +		{
   1.205 +		// if locked queue is empty, add it onto the locked queue directly
   1.206 +		AddFirstOntoQueue(aPage, TDynamicDirCachePage::ELocked);
   1.207 +		}
   1.208 +	else
   1.209 +		{
   1.210 +		// otherwise, we squeeze for the last position on locked queue
   1.211 +		while (iLockedQCount + 1 >= iMinSizeInPages)
   1.212 +			{
   1.213 +			TDynamicDirCachePage* last = iLockedQ.Last();
   1.214 +			DeQueue(last);
   1.215 +			UnlockPage(last);
   1.216 +			AddFirstOntoQueue(last, TDynamicDirCachePage::EUnlocked);
   1.217 +			}
   1.218 +
   1.219 +		// iLockedQCount + 1 < iMinSizeInPages
   1.220 +		iLockedQ.AddLast(*aPage);
   1.221 +		aPage->SetPageType(TDynamicDirCachePage::ELocked);
   1.222 +		iLockedQCount++;
   1.223 +		}
   1.224 +	}
   1.225 +
   1.226 +/**
   1.227 +    Read data from a single page. If the page is not found or not valid anymore, read media onto iActive page first.
   1.228 +    The data will be _Appended_ the the descriptor aDes. The caller is responsible for maintaining this descriptor.
   1.229 +
   1.230 +    @param	aPos	the starting position of the media address to be read.
   1.231 +    @param	aLength	the length of the content to be read.
   1.232 +    @param	aDes	the descriptor to contain the content.
   1.233 +    @pre	aLength should be no more than page size.
   1.234 +*/
   1.235 +void CDynamicDirCache::ReadDataFromSinglePageL(TInt64 aPos, TInt aLength, TDes8& aDes)
   1.236 +	{
   1.237 +    //-- the data section is in the cache page entirely, take data directly from the cache
   1.238 +	TDynamicDirCachePage* pPage = FindPageByPos(aPos);
   1.239 +    if (pPage)
   1.240 +    	{
   1.241 +		// lock page before reading,
   1.242 +    	if (LockPage(pPage) != NULL)
   1.243 +    		{
   1.244 +    		// read data and append them to the descriptor
   1.245 +            aDes.Append(pPage->PtrInPage(aPos), aLength);
   1.246 +
   1.247 +
   1.248 +            // if page is from unlocked queue, insert it onto the last page of the locked
   1.249 +            //  queue. this is to avoid excessive locking and unlocking operations that is
   1.250 +            //  highly likely to happen for following reads.
   1.251 +            if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
   1.252 +            	{
   1.253 +            	DeQueue(pPage);
   1.254 +            	MakePageLastLocked(pPage);
   1.255 +            	}
   1.256 +    		}
   1.257 +    	else	// page locking failed
   1.258 +    		{
   1.259 +    		ASSERT(pPage->PageType() == TDynamicDirCachePage::EUnlocked);
   1.260 +    		DeQueue(pPage);
   1.261 +    		LookupTblRemove(pPage->StartPos());
   1.262 +    		DecommitPage(pPage);
   1.263 +    		delete pPage;
   1.264 +    		pPage = NULL;
   1.265 +    		}
   1.266 +    	}
   1.267 +
   1.268 +	if (!pPage)
   1.269 +		{
   1.270 +        // if page not found or page data not valid anymore, use active page to read data in
   1.271 +        pPage = UpdateActivePageL(aPos);
   1.272 +        // read data and append them to the descriptor
   1.273 +        aDes.Append(pPage->PtrInPage(aPos), aLength);
   1.274 +    	}
   1.275 +
   1.276 +	}
   1.277 +
   1.278 +//====================================================================
   1.279 +/**
   1.280 +Implementation of pure virtual function.
   1.281 +@see	MWTCacheInterface::ReadL()
   1.282 +*/
   1.283 +void CDynamicDirCache::ReadL(TInt64 aPos, TInt aLength, TDes8& aDes)
   1.284 +	{
   1.285 +#ifdef _DEBUG
   1.286 +    if(iCacheDisabled)
   1.287 +        {
   1.288 +        // cache is disabled for debug purposes
   1.289 +        __PRINT(_L("CDynamicDirCache disabled"));
   1.290 +        User::LeaveIfError(iDrive.ReadNonCritical(aPos, aLength, aDes));
   1.291 +        return;
   1.292 +        }
   1.293 +#endif //_DEBUG
   1.294 +
   1.295 +    aDes.Zero();
   1.296 +    const TUint32 PageSz = iPageSizeInBytes;//-- cache page size
   1.297 +
   1.298 +    TInt64 pageStartMedPos = CalcPageStartPos(aPos);
   1.299 +    const TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos); //-- number of bytes from aPos to the end of the page
   1.300 +
   1.301 +//    __PRINT5(_L("CDynamicDirCache::ReadL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, aLength, pageStartMedPos, PageSz, bytesToPageEnd);
   1.302 +    // if all data needed is on a single page
   1.303 +    if((TUint32)aLength <= bytesToPageEnd)
   1.304 +        {
   1.305 +        ReadDataFromSinglePageL(aPos, aLength, aDes);
   1.306 +        }
   1.307 +    // or data to be read cross cache page boundary or probably we have more than 1 page to read
   1.308 +    else
   1.309 +        {
   1.310 +        __PRINT(_L("CDynamicDirCache::ReadL() CROSS PAGE!"));
   1.311 +        TUint32 dataLen(aLength);   //-- current data length
   1.312 +        TInt64  currMediaPos(aPos); //-- current media position
   1.313 +
   1.314 +        //-- 1. read data that are already in the current page
   1.315 +        ReadDataFromSinglePageL(currMediaPos, bytesToPageEnd, aDes);
   1.316 +        dataLen -= bytesToPageEnd;
   1.317 +        currMediaPos += bytesToPageEnd;
   1.318 +
   1.319 +        //-- 2. read whole pages of data
   1.320 +        while (dataLen >= PageSz)
   1.321 +        	{
   1.322 +        	//-- find out if currMediaPos is in cache. If not, find a spare page and read data there
   1.323 +            ReadDataFromSinglePageL(currMediaPos, PageSz, aDes);
   1.324 +            currMediaPos += PageSz;
   1.325 +            dataLen -= PageSz;
   1.326 +        	}
   1.327 +
   1.328 +        //-- 3. read the rest of the data
   1.329 +        if(dataLen > 0)
   1.330 +            {
   1.331 +            ReadDataFromSinglePageL(currMediaPos, dataLen, aDes);
   1.332 +            }
   1.333 +        } //else((TUint32)aLength <= bytesToPageEnd)
   1.334 +	}
   1.335 +
   1.336 +/**
   1.337 +Write data through a single page. If the page is not found or not valid anymore, read media onto iActive page
   1.338 +first, then write data through iActive page.
   1.339 +@param	aPos	the starting position of the media address to be write.
   1.340 +@param	aData	the starting address that the writing content lives in the ram.
   1.341 +@param	aDataLen	the length of the content to be written.
   1.342 +@pre	aDataLen	should be no more than page size.
   1.343 +*/
   1.344 +void CDynamicDirCache::WriteDataOntoSinglePageL(TInt64 aPos, const TUint8* aData, TUint32 aDataLen)
   1.345 +	{
   1.346 +	ASSERT(aDataLen <= iPageSizeInBytes);
   1.347 +    //-- the data section is in the cache page entirely, take data directly from the cache
   1.348 +	TDynamicDirCachePage* pPage = FindPageByPos(aPos);
   1.349 +    if (pPage)
   1.350 +    	{
   1.351 +		// lock page before writing,
   1.352 +    	if (LockPage(pPage) != NULL)
   1.353 +    		{
   1.354 +    		//-- update cache
   1.355 +            Mem::Copy(pPage->PtrInPage(aPos), aData, aDataLen);
   1.356 +    		}
   1.357 +    	else
   1.358 +    		{
   1.359 +    		ASSERT(pPage->PageType() == TDynamicDirCachePage::EUnlocked);
   1.360 +    		DeQueue(pPage);
   1.361 +    		LookupTblRemove(pPage->StartPos());
   1.362 +    		DecommitPage(pPage);
   1.363 +    		delete pPage;
   1.364 +    		pPage = NULL;
   1.365 +    		}
   1.366 +    	}
   1.367 +
   1.368 +    // if page not found or page data not valid anymore, use active page to read data in
   1.369 +    if (!pPage)
   1.370 +    	{
   1.371 +        pPage = UpdateActivePageL(aPos);
   1.372 +        //-- update cache
   1.373 +        Mem::Copy(pPage->PtrInPage(aPos), aData, aDataLen);
   1.374 +    	}
   1.375 +
   1.376 +	// make sure the page is unlocked after use
   1.377 +	if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
   1.378 +		{
   1.379 +		UnlockPage(pPage);
   1.380 +		}
   1.381 +
   1.382 +	// always make writting events MRU
   1.383 +	DoMakePageMRU(aPos);
   1.384 +    return;
   1.385 +	}
   1.386 +
   1.387 +/**
   1.388 +Implementation of pure virtual function.
   1.389 +@see	MWTCacheInterface::WriteL()
   1.390 +*/
   1.391 +void CDynamicDirCache::WriteL(TInt64 aPos,const TDesC8& aDes)
   1.392 +	{
   1.393 +#ifdef _DEBUG
   1.394 +    if(iCacheDisabled)
   1.395 +        {
   1.396 +        // cache is disabled for debug purposes
   1.397 +        __PRINT(_L("CDynamicDirCache disabled"));
   1.398 +        User::LeaveIfError(iDrive.WriteCritical(aPos,aDes));
   1.399 +        return;
   1.400 +        }
   1.401 +#endif //_DEBUG
   1.402 +
   1.403 +    TUint32 dataLen = aDes.Size();
   1.404 +    const TUint8* pData   = aDes.Ptr();
   1.405 +    const TUint32 PageSz  = iPageSizeInBytes; //-- cache page size
   1.406 +
   1.407 +    TInt64 pageStartMedPos = CalcPageStartPos(aPos);
   1.408 +    TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos);
   1.409 +
   1.410 +//    __PRINT5(_L("CDynamicDirCache::WriteL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, dataLen, pageStartMedPos, PageSz, bytesToPageEnd);
   1.411 +
   1.412 +    if(dataLen <= bytesToPageEnd)
   1.413 +        {
   1.414 +        WriteDataOntoSinglePageL(aPos, pData, dataLen);
   1.415 +        }
   1.416 +    else
   1.417 +        {
   1.418 +        __PRINT(_L("CDynamicDirCache::WriteL() CROSS PAGE!"));
   1.419 +
   1.420 +        //-- Data to be written cross cache page boundary or probably we have more than 1 page to write
   1.421 +        TInt64  currMediaPos(aPos);
   1.422 +
   1.423 +        //-- 1. update the current page
   1.424 +        WriteDataOntoSinglePageL(currMediaPos, pData, bytesToPageEnd);
   1.425 +
   1.426 +        pData += bytesToPageEnd;
   1.427 +        currMediaPos += bytesToPageEnd;
   1.428 +        dataLen -= bytesToPageEnd;
   1.429 +
   1.430 +        //-- 2. write whole pages of data to the cache
   1.431 +        while (dataLen >= PageSz)
   1.432 +        	{
   1.433 +            WriteDataOntoSinglePageL(currMediaPos, pData, PageSz);
   1.434 +
   1.435 +            pData += PageSz;
   1.436 +            currMediaPos += PageSz;
   1.437 +            dataLen -= PageSz;
   1.438 +        	}
   1.439 +
   1.440 +        //-- 3. write the rest of the data
   1.441 +        if(dataLen > 0)
   1.442 +            {
   1.443 +            WriteDataOntoSinglePageL(currMediaPos, pData, dataLen);
   1.444 +            }
   1.445 +        }// else(dataLen <= bytesToPageEnd)
   1.446 +
   1.447 +
   1.448 +    //-- write data to the media
   1.449 +    const TInt nErr = iDrive.WriteCritical(aPos,aDes);
   1.450 +    if(nErr != KErrNone)
   1.451 +        {//-- some serious problem occured during writing, invalidate cache.
   1.452 +        InvalidateCache();
   1.453 +        User::Leave(nErr);
   1.454 +        }
   1.455 +	}
   1.456 +
   1.457 +/**
   1.458 +    Invalidate the cache
   1.459 +    @see	MWTCacheInterface::InvalidateCache()
   1.460 +*/
   1.461 +void CDynamicDirCache::DoInvalidateCache(void)
   1.462 +	{
   1.463 +	__PRINT2(_L("CDynamicDirCache::InvalidateCache(locked=%d, unlocked=%d)"), iLockedQCount, iUnlockedQCount);
   1.464 +	// we should never decommit locked pages as they needs to be reserved anyway
   1.465 +	// the overhead of unnecessary page committing operations
   1.466 +
   1.467 +	TInt pagesToRemoveFromLockedQueue = iLockedQCount - iPermanentlyAllocatedPageCount;
   1.468 +	TInt n;
   1.469 +	for (n=0; n<pagesToRemoveFromLockedQueue; n++)
   1.470 +		{
   1.471 +		TDynamicDirCachePage* page = iLockedQ.Last();
   1.472 +		DeQueue(page);						// remove from queue
   1.473 +		LookupTblRemove(page->StartPos());	// remove from lookuptable
   1.474 +		DecommitPage(page);					// inform cache client to decommit page memory
   1.475 +		delete page;
   1.476 +		}
   1.477 +	ASSERT(iLockedQCount == iPermanentlyAllocatedPageCount);
   1.478 +
   1.479 +	TDblQueIter<TDynamicDirCachePage> q(iLockedQ);
   1.480 +	q.SetToFirst();
   1.481 +	while((TDynamicDirCachePage*) q)
   1.482 +		{
   1.483 +		TDynamicDirCachePage* page = q++;
   1.484 +		LookupTblRemove(page->StartPos());// remove from lookuptable
   1.485 +		ResetPagePos(page);				// reset start media position (0), invalidate page content
   1.486 +		}
   1.487 +
   1.488 +	// however we should decommit unlocked pages here
   1.489 +	while (!iUnlockedQ.IsEmpty())
   1.490 +		{
   1.491 +		TDynamicDirCachePage* page = iUnlockedQ.Last();
   1.492 +		DeQueue(page);						// remove from queue
   1.493 +		LookupTblRemove(page->StartPos());	// remove from lookuptable
   1.494 +		DecommitPage(page);					// inform cache client to decommit page memory
   1.495 +		delete page;
   1.496 +		}
   1.497 +	ASSERT(iUnlockedQCount == 0);
   1.498 +
   1.499 +	ASSERT(iLockedQCount == iPermanentlyAllocatedPageCount);
   1.500 +
   1.501 +	ASSERT(iCacheMemoryClient);
   1.502 +	}
   1.503 +
   1.504 +/**
   1.505 +Implementation of pure virtual function.
   1.506 +@see	MWTCacheInterface::InvalidateCache()
   1.507 +*/
   1.508 +void CDynamicDirCache::InvalidateCache(void)
   1.509 +	{
   1.510 +	DoInvalidateCache();
   1.511 +	}
   1.512 +
   1.513 +/** this method isn't implemented*/
   1.514 +void CDynamicDirCache::InvalidateCachePage(TUint64 /*aPos*/)
   1.515 +    {
   1.516 +    ASSERT(0);
   1.517 +    }
   1.518 +
   1.519 +
   1.520 +/**
   1.521 +Implementation of pure virtual function.
   1.522 +@see	MWTCacheInterface::PosCached()
   1.523 +*/
   1.524 +TUint32 CDynamicDirCache::PosCached(const TInt64& aPos, TInt64& aCachedPosStart)
   1.525 +	{
   1.526 +	const TInt64 pageStartMedPos = CalcPageStartPos(aPos);
   1.527 +
   1.528 +	// only search the page in lookup table
   1.529 +	// NOTE: we don't count the active page into acount here,
   1.530 +	// this is to avoid pulling next pages recursively
   1.531 +	TDynamicDirCachePage* pPage = LookupTblFind(pageStartMedPos);
   1.532 +
   1.533 +	// then check if page is still valid if page is on Unlocked Page Queue
   1.534 +	if (pPage && pPage->PageType() == TDynamicDirCachePage::EUnlocked)
   1.535 +		{
   1.536 +		if (LockPage(pPage) != NULL)
   1.537 +			{
   1.538 +//			__PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) found on Unlocked Queue!"), aPos);
   1.539 +			// have to unlock it before returning, otherwise there will be memory leak
   1.540 +			UnlockPage(pPage);
   1.541 +    	    aCachedPosStart = pPage->StartPos();
   1.542 +			return pPage->PageSizeInBytes();
   1.543 +			}
   1.544 +		else	// if the unlocked page is not valid anymore, remove it
   1.545 +			{
   1.546 +    		DeQueue(pPage);
   1.547 +    		LookupTblRemove(pPage->StartPos());
   1.548 +    		DecommitPage(pPage);
   1.549 +    		delete pPage;
   1.550 +    		pPage = NULL;
   1.551 +			}
   1.552 +		}
   1.553 +	// otherwise if page is already locked or valid active page
   1.554 +	else if (pPage)
   1.555 +		{
   1.556 +		__PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) on Locked Queue!"), aPos);
   1.557 +	    aCachedPosStart = pPage->StartPos();
   1.558 +		return pPage->PageSizeInBytes();
   1.559 +		}
   1.560 +
   1.561 +	// page is not found or not valid anymore
   1.562 +	return 0;
   1.563 +	}
   1.564 +
   1.565 +/**
   1.566 +Implementation of pure virtual function.
   1.567 +@see	MWTCacheInterface::CacheSizeInBytes()
   1.568 +*/
   1.569 +TUint32 CDynamicDirCache::CacheSizeInBytes()  const
   1.570 +	{
   1.571 +	return iMaxCacheSizeInBytes;
   1.572 +	}
   1.573 +
   1.574 +/**
   1.575 +Implementation of pure virtual function.
   1.576 +@see	MWTCacheInterface::Control()
   1.577 +*/
   1.578 +TInt CDynamicDirCache::Control(TUint32 aFunction, TUint32 aParam1, TAny* aParam2)
   1.579 +	{
   1.580 +    TInt r = KErrNotSupported;
   1.581 +#ifdef _DEBUG
   1.582 +    (void)aParam2;
   1.583 +    switch(aFunction)
   1.584 +        {
   1.585 +        // disable / enable cache, for debug
   1.586 +        // if aParam1 != 0 cache will be disabled, enabled otherwise
   1.587 +        case EDisableCache:
   1.588 +            iCacheDisabled = aParam1 ? 1 : 0;
   1.589 +            r = KErrNone;
   1.590 +        break;
   1.591 +
   1.592 +        // dump cache, for debug
   1.593 +        case EDumpCache:
   1.594 +        	{
   1.595 +        	RFs fs;
   1.596 +        	fs.Connect();
   1.597 +        	const TUint32 debugRegister = DebugRegister();
   1.598 +        	fs.SetDebugRegister(debugRegister|KFSYS);
   1.599 +        	Dump();
   1.600 +        	fs.SetDebugRegister(debugRegister);
   1.601 +        	fs.Close();
   1.602 +        	break;
   1.603 +        	}
   1.604 +        case ECacheInfo:
   1.605 +        	{
   1.606 +        	RFs fs;
   1.607 +        	fs.Connect();
   1.608 +        	const TUint32 debugRegister = DebugRegister();
   1.609 +        	fs.SetDebugRegister(debugRegister|KFSYS);
   1.610 +        	Info();
   1.611 +        	fs.SetDebugRegister(debugRegister);
   1.612 +        	fs.Close();
   1.613 +        	break;
   1.614 +        	}
   1.615 +
   1.616 +        default:
   1.617 +            __PRINT1(_L("CDynamicDirCache::Control() invalid function: %d"), aFunction);
   1.618 +            ASSERT(0);
   1.619 +        break;
   1.620 +        }
   1.621 +
   1.622 +#else
   1.623 +    (void)aFunction; //-- supress warnings
   1.624 +    (void)aParam1;
   1.625 +    (void)aParam2;
   1.626 +    User::Invariant(); //-- don't call this method in release build
   1.627 +#endif //_DEBUG
   1.628 +
   1.629 +    return r;
   1.630 +	}
   1.631 +
   1.632 +/**
   1.633 +Implementation of pure virtual function.
   1.634 +@see	MWTCacheInterface::SetCacheBasePos()
   1.635 +*/
   1.636 +void CDynamicDirCache::SetCacheBasePos(TInt64 aBasePos)
   1.637 +	{
   1.638 +	iCacheBasePos = aBasePos;
   1.639 +	}
   1.640 +
   1.641 +/**
   1.642 +Implementation of pure virtual function.
   1.643 +@see	MWTCacheInterface::SetCacheBasePos()
   1.644 +*/
   1.645 +TUint32 CDynamicDirCache::PageSizeInBytesLog2() const
   1.646 +	{
   1.647 +	return iPageSizeLog2;
   1.648 +	}
   1.649 +
   1.650 +
   1.651 +void CDynamicDirCache::DoMakePageMRU(TInt64 aPos)
   1.652 +	{
   1.653 +//	__PRINT1(_L("MakePageMRU (%lx)"), aPos);
   1.654 +//	__PRINT4(_L("Current Cache State: iLockedQCount=%d, iUnlockedQCount=%d, iLookupTbl=%d, iMaxSizeInPages=%d"), iLockedQCount, iUnlockedQCount, iLookupTable.Count(), iMaxSizeInPages);
   1.655 +	// check the MRU page first, if it is already the MRU page, we can return immediately
   1.656 +	TInt64 pageStartMedPos = CalcPageStartPos(aPos);
   1.657 +	if (!iLockedQ.IsEmpty())
   1.658 +		{
   1.659 +		if (iLockedQ.First()->StartPos() == pageStartMedPos)
   1.660 +			{
   1.661 +			return;
   1.662 +			}
   1.663 +		}
   1.664 +
   1.665 +	TDynamicDirCachePage* pPage = FindPageByPos(aPos);
   1.666 +    if (pPage)
   1.667 +    	{
   1.668 +    	ASSERT(pPage->IsValid());
   1.669 +		// lock page before make it MRU
   1.670 +    	if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
   1.671 +    		{
   1.672 +    		ASSERT(!pPage->IsLocked());
   1.673 +        	if (LockPage(pPage) == NULL)
   1.674 +        		{
   1.675 +        		DeQueue(pPage);
   1.676 +        		LookupTblRemove(pPage->StartPos());
   1.677 +        		DecommitPage(pPage);
   1.678 +        		delete pPage;
   1.679 +        		pPage = NULL;
   1.680 +        		}
   1.681 +    		}
   1.682 +    	else
   1.683 +    		{
   1.684 +    		// error checking: page should either be locked or active
   1.685 +    		ASSERT(LockPage(pPage) != NULL);
   1.686 +    		}
   1.687 +    	}
   1.688 +
   1.689 +    // if page not found or page data not valid anymore, use active page to read data
   1.690 +    if (!pPage)
   1.691 +    	{
   1.692 +        TRAPD(err, pPage = UpdateActivePageL(aPos));
   1.693 +        if (err != KErrNone)
   1.694 +        	{
   1.695 +        	// problem occurred reading active page, return immediately.
   1.696 +        	return;
   1.697 +        	}
   1.698 +    	}
   1.699 +
   1.700 +    // by now, the page is either locked or active page
   1.701 +	ASSERT(pPage && pPage->IsValid() && pPage->IsLocked());
   1.702 +
   1.703 +
   1.704 +
   1.705 +	TBool allocateNewPage = pPage == iLockedQ.Last() && !CacheIsFull();
   1.706 +
   1.707 +
   1.708 +	switch (pPage->PageType())
   1.709 +		{
   1.710 +		case TDynamicDirCachePage::EUnlocked:
   1.711 +			{
   1.712 +			// if page was originally on Unlocked Page Queque, remove it from Unlocked Page Queue, add it
   1.713 +			// to the Locked Page Queue and make it MRU
   1.714 +			DeQueue(pPage);
   1.715 +			AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
   1.716 +			// check cache limit
   1.717 +			CheckThresholds();
   1.718 +			}
   1.719 +		case TDynamicDirCachePage::ELocked:
   1.720 +			{
   1.721 +			// otherwise the page was on Locked Page Queue, make it MRU
   1.722 +			// no need to check cache limit
   1.723 +			if (pPage != iLockedQ.First())
   1.724 +				{
   1.725 +				DeQueue(pPage);
   1.726 +				AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
   1.727 +				}
   1.728 +			break;
   1.729 +			}
   1.730 +		default:
   1.731 +			ASSERT(0);
   1.732 +		}
   1.733 +
   1.734 +	if (allocateNewPage)
   1.735 +		{
   1.736 +		TDynamicDirCachePage* nPage = NULL;
   1.737 +		TRAPD(err, nPage = AllocateAndLockNewPageL(0));
   1.738 +		if (err == KErrNone)
   1.739 +			{
   1.740 +
   1.741 +			// about to add a page to end of locked queue, so lie about iLockedQCount
   1.742 +			iLockedQCount++;
   1.743 +			CheckThresholds();
   1.744 +			iLockedQCount--;
   1.745 +
   1.746 +			iLockedQ.AddLast(*nPage);
   1.747 +			nPage->SetPageType(TDynamicDirCachePage::ELocked);
   1.748 +			++iLockedQCount;
   1.749 +			LookupTblAdd(nPage);
   1.750 +			}
   1.751 +		}
   1.752 +	}
   1.753 +
   1.754 +/**
   1.755 +    Implementation of pure virtual function.
   1.756 +    @see	MDiskSpecialAccessor::MakePageMRU()
   1.757 +*/
   1.758 +void CDynamicDirCache::MakePageMRU(TInt64 aPos)
   1.759 +	{
   1.760 +	DoMakePageMRU(aPos);
   1.761 +	}
   1.762 +
   1.763 +//====================================================================
   1.764 +/**
   1.765 +Internal query function, to check if aPos is cached or not. iActive page is included in searching.
   1.766 +*/
   1.767 +TDynamicDirCachePage* CDynamicDirCache::FindPageByPos(TInt64 aPos)
   1.768 +	{
   1.769 +//	__PRINT1(_L("CDynamicDirCache::FindPageByPos(aPos=%lx)"), aPos);
   1.770 +    // align the page position
   1.771 +	TInt64 pageStartMedPos = CalcPageStartPos(aPos);
   1.772 +
   1.773 +	// search in lookup table
   1.774 +	return LookupTblFind(pageStartMedPos);
   1.775 +	}
   1.776 +
   1.777 +/**
   1.778 +read a page length data into iActive page and return iActive page if read is successful.
   1.779 +*/
   1.780 +TDynamicDirCachePage* CDynamicDirCache::UpdateActivePageL(TInt64 aPos)
   1.781 +	{
   1.782 +    // align the page position
   1.783 +	TInt64 pageStartMedPos = CalcPageStartPos(aPos);
   1.784 +
   1.785 +	ASSERT(!iLockedQ.IsEmpty());
   1.786 +	TDynamicDirCachePage* activePage = iLockedQ.Last();
   1.787 +
   1.788 +	if (activePage->StartPos() == pageStartMedPos && activePage->IsValid())
   1.789 +		{
   1.790 +		return activePage;
   1.791 +		}
   1.792 +
   1.793 +	__PRINT2(_L("CDynamicDirCache::UpdateActivePageL(aPos=%lx, active=%lx)"), aPos, activePage->StartPos());
   1.794 +
   1.795 +	activePage->Deque();
   1.796 +	LookupTblRemove(activePage->StartPos());
   1.797 +
   1.798 +	// set start med pos value, no other effects, only available to active page
   1.799 +	activePage->SetPos(pageStartMedPos);
   1.800 +
   1.801 +	// read data, make active page valid
   1.802 +	TUint8* data = activePage->PtrInPage(activePage->iStartMedPos);
   1.803 +    TPtr8 dataPtr(data, iPageSizeInBytes);
   1.804 +	
   1.805 +    const TInt nErr = iDrive.ReadNonCritical(activePage->iStartMedPos, iPageSizeInBytes, dataPtr);
   1.806 +
   1.807 +	iLockedQ.AddLast(*activePage);
   1.808 +	LookupTblAdd(activePage);
   1.809 +
   1.810 +    if(nErr !=KErrNone)
   1.811 +        {
   1.812 +        // some serious problem occured during reading, invalidate cache.
   1.813 +        DoInvalidateCache();
   1.814 +        User::Leave(nErr);
   1.815 +        }
   1.816 +    activePage->SetValid(ETrue);
   1.817 +
   1.818 +    return activePage;
   1.819 +	}
   1.820 +
   1.821 +/**
   1.822 +Check if the number of (locked pages + iActive page) and unlocked pages have exceeded minimum allowed page
   1.823 +number and maximum allowed page number respectively.
   1.824 +*/
   1.825 +void CDynamicDirCache::CheckThresholds()
   1.826 +	{
   1.827 +	while (iLockedQCount + 1 > iMinSizeInPages)
   1.828 +		{
   1.829 +		TDynamicDirCachePage* movePage = iLockedQ.Last();
   1.830 +		UnlockPage(movePage);
   1.831 +		DeQueue(movePage);
   1.832 +		TInt err = LookupTblRemove(movePage->StartPos());
   1.833 +		ASSERT(err == KErrNone);
   1.834 +
   1.835 +		// if it is a valid page, add onto unlocked queue
   1.836 +		if (movePage->StartPos() != 0)
   1.837 +			{
   1.838 +			ASSERT(movePage->IsValid());
   1.839 +			AddFirstOntoQueue(movePage, TDynamicDirCachePage::EUnlocked);
   1.840 +			err = LookupTblAdd(movePage);
   1.841 +			ASSERT(err == KErrNone);
   1.842 +			}
   1.843 +		else // reserved page, delete
   1.844 +			{
   1.845 +			DecommitPage(movePage);
   1.846 +			delete movePage;
   1.847 +			}
   1.848 +		}
   1.849 +
   1.850 +	// if unlocked queue exceeds limit, delete LRU page
   1.851 +	// note: all pages on unlocked queue should be valid
   1.852 +	while (iUnlockedQCount > iMaxSizeInPages - iMinSizeInPages)
   1.853 +		{
   1.854 +		TDynamicDirCachePage* removePage = iUnlockedQ.Last();
   1.855 +		ASSERT(removePage->StartPos() != 0 && removePage->IsValid());
   1.856 +		DeQueue(removePage);
   1.857 +		LookupTblRemove(removePage->StartPos());
   1.858 +		DecommitPage(removePage);
   1.859 +		delete removePage;
   1.860 +		}
   1.861 +	}
   1.862 +
   1.863 +/**
   1.864 +Try to create a new page and lock the page content when it is created. This function should only be called
   1.865 +when creating iActive page or making a page MRU (which might result in page evictions).
   1.866 +@return	the pointer of the newly created page, or NULL if allocation failed.
   1.867 +@param	aStartMedPos	the starting media address of the page to be created.
   1.868 +@pre	aStartMedPos should not already be existing in the cache.
   1.869 +*/
   1.870 +TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPageL(TInt64 aStartMedPos)
   1.871 +	{
   1.872 +	__PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPageL(aStartMedPos=%lx)"), aStartMedPos);
   1.873 +
   1.874 +	TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs());
   1.875 +	if (startRamAddr)
   1.876 +		{
   1.877 +		// create new page and return
   1.878 +		TDynamicDirCachePage* pPage = TDynamicDirCachePage::NewL(this, aStartMedPos, startRamAddr);
   1.879 +		pPage->SetLocked(ETrue);
   1.880 +		pPage->SetValid(EFalse);
   1.881 +		return pPage;
   1.882 +		}
   1.883 +
   1.884 +	return NULL;
   1.885 +	}
   1.886 +
   1.887 +#ifdef _DEBUG
   1.888 +/**
   1.889 +Dump cache information, only enabled in debug mode.
   1.890 +@see CDynamicDirCache::Control()
   1.891 +*/
   1.892 +void CDynamicDirCache::Info() const
   1.893 +	{
   1.894 +	__PRINT(_L("======== CDynamicDirCache::Info ========="));
   1.895 +	const TUint32 SegmentSizeInBytesLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2();
   1.896 +	// page size
   1.897 +	__PRINT1(_L("=== Pages size:               [%d Bytes]"), iPageSizeInBytes);
   1.898 +	__PRINT1(_L("=== Segment size:             [%d Bytes]"), 1 << SegmentSizeInBytesLog2);
   1.899 +
   1.900 +	// data size:
   1.901 +	__PRINT1(_L("=== Min data size:            [%d Bytes]"), iMinSizeInPages << iPageSizeLog2);
   1.902 +	__PRINT1(_L("=== Max data size:            [%d Bytes]"), iMaxSizeInPages << iPageSizeLog2);
   1.903 +
   1.904 +	// memory size:
   1.905 +	const TUint32 pageMemSizeLog2 = iPageSizeLog2 > SegmentSizeInBytesLog2 ? iPageSizeLog2 : SegmentSizeInBytesLog2;
   1.906 +	__PRINT1(_L("=== Min memory size:          [%d Bytes]"), iMinSizeInPages << pageMemSizeLog2);
   1.907 +	__PRINT1(_L("=== Max memory size:          [%d Bytes]"), iMaxSizeInPages << pageMemSizeLog2);
   1.908 +
   1.909 +	// reserved pages
   1.910 +	__PRINT1(_L("=== Number of pages reserved: [%d]"), iMinSizeInPages);
   1.911 +	__PRINT1(_L("=== Reserved memory:          [%d Bytes]"), (iMinSizeInPages * PageSizeInSegs()) << SegmentSizeInBytesLog2);
   1.912 +	// locked page num
   1.913 +	__PRINT1(_L("=== Number of pages locked:   [%d]"), iLockedQCount);
   1.914 +	__PRINT1(_L("=== Locked memory:            [%d Bytes]"), (iLockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2);
   1.915 +	// unlocked page num
   1.916 +	__PRINT1(_L("=== Number of pages unlocked: [%d]"), iUnlockedQCount);
   1.917 +	__PRINT1(_L("=== Unlocked memory:          [%d Bytes]"), (iUnlockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2);
   1.918 +	}
   1.919 +
   1.920 +/**
   1.921 +Dump cache content, only enabled in debug mode.
   1.922 +@see CDynamicDirCache::Control()
   1.923 +*/
   1.924 +void CDynamicDirCache::Dump()
   1.925 +	{
   1.926 +	__PRINT(_L("======== CDynamicDirCache::Dump ========="));
   1.927 +	if (!iLockedQ.IsEmpty())
   1.928 +		{
   1.929 +		TDblQueIter<TDynamicDirCachePage> q(iLockedQ);
   1.930 +		q.SetToFirst();
   1.931 +		TInt i = 0;
   1.932 +		while((TDynamicDirCachePage*)q)
   1.933 +			{
   1.934 +			TDynamicDirCachePage* pP = q++;
   1.935 +			__PRINT5(_L("=== CDynamicDirCache::iLockedQ\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes());
   1.936 +			}
   1.937 +		}
   1.938 +	if (!iUnlockedQ.IsEmpty())
   1.939 +		{
   1.940 +		TDblQueIter<TDynamicDirCachePage> q(iUnlockedQ);
   1.941 +		q.SetToFirst();
   1.942 +		TInt i = 0;
   1.943 +		while((TDynamicDirCachePage*)q)
   1.944 +			{
   1.945 +			TDynamicDirCachePage* pP = q++;
   1.946 +			__PRINT5(_L("=== CDynamicDirCache::iUnlockedQ\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes());
   1.947 +			}
   1.948 +		}
   1.949 +
   1.950 +	if (iLookupTable.Count())
   1.951 +		{
   1.952 +		TInt i = 0;
   1.953 +		THashSetIter<TLookupEntry> iter(iLookupTable);
   1.954 +		TLookupEntry* pEntry;
   1.955 +		pEntry = (TLookupEntry*) iter.Next();
   1.956 +		while(pEntry)
   1.957 +			{
   1.958 +			TDynamicDirCachePage* pP = pEntry->iPage;
   1.959 +			__PRINT5(_L("=== CDynamicDirCache::iLookupTable\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes());
   1.960 +			pEntry = (TLookupEntry*) iter.Next();
   1.961 +			};
   1.962 +		}
   1.963 +	__PRINT(_L("===========================================\n"));
   1.964 +	}
   1.965 +#endif //_DEBUG
   1.966 +
   1.967 +/**
   1.968 +Lock an unlocked page, or do nothing if the page is already locked.
   1.969 +@return	TUint8*	pointer of the page to be locked, if locking is successful, otherwise return NULL.
   1.970 +@param	aPage	the pointer of the page to be locked.
   1.971 +*/
   1.972 +TUint8* CDynamicDirCache::LockPage(TDynamicDirCachePage* aPage)
   1.973 +	{
   1.974 +	ASSERT(aPage != NULL);
   1.975 +	if (aPage->IsLocked())
   1.976 +		return aPage->StartPtr();
   1.977 +
   1.978 +	TInt r = iCacheMemoryClient->LockSegments(aPage->StartPtr(), PageSizeInSegs());
   1.979 +	if (r == KErrNone)
   1.980 +		{
   1.981 +		aPage->SetLocked(ETrue);
   1.982 +		return aPage->StartPtr();
   1.983 +		}
   1.984 +
   1.985 +	return NULL;
   1.986 +	}
   1.987 +
   1.988 +/**
   1.989 +Unlock a locked page.
   1.990 +@return	TInt	KErrNone if unlocking was successful, otherwise system-wide error code.
   1.991 +@param	aPage	the pointer of the page to be unlocked.
   1.992 +*/
   1.993 +TInt CDynamicDirCache::UnlockPage(TDynamicDirCachePage* aPage)
   1.994 +	{
   1.995 +	ASSERT(aPage != NULL);
   1.996 +	__PRINT1(_L("CDynamicDirCache::UnlockPage(%lx)"), aPage->StartPos());
   1.997 +	TInt r = iCacheMemoryClient->UnlockSegments(aPage->StartPtr(), PageSizeInSegs());
   1.998 +	if (r == KErrNone)
   1.999 +		{
  1.1000 +		aPage->SetLocked(EFalse);
  1.1001 +		}
  1.1002 +	return r;
  1.1003 +	}
  1.1004 +
  1.1005 +/**
  1.1006 +Decommit a locked or unlocked page.
  1.1007 +@return	TInt	KErrNone if decommition was successful, otherwise system-wide error code.
  1.1008 +@param	aPage	the pointer of the page to be decommitted.
  1.1009 +*/
  1.1010 +TInt CDynamicDirCache::DecommitPage(TDynamicDirCachePage* aPage)
  1.1011 +	{
  1.1012 +	ASSERT(aPage != NULL);
  1.1013 +	__PRINT1(_L("CDynamicDirCache::DecommitPage(%lx)"), aPage->StartPos());
  1.1014 +	if (aPage)
  1.1015 +		{
  1.1016 +		TInt r = iCacheMemoryClient->DecommitSegments(aPage->StartPtr(), PageSizeInSegs());
  1.1017 +		if (r == KErrNone)
  1.1018 +			{
  1.1019 +			aPage->SetLocked(EFalse);
  1.1020 +			aPage->SetValid(EFalse);
  1.1021 +			}
  1.1022 +		return r;
  1.1023 +		}
  1.1024 +	return KErrArgument;
  1.1025 +	}
  1.1026 +
  1.1027 +/////////////////////////// aluxiliary functions //////////////////////////////////
  1.1028 +/**
  1.1029 +Calculate the page size in segments. Segment size is the size of the kernel memory unit that cache memory manager manages.
  1.1030 +We are making assumption here about the page size: page size should always be either less than segment size
  1.1031 +or multiple times of segment size
  1.1032 +@return	TUint32	the page size in segments.
  1.1033 +*/
  1.1034 +TUint32 CDynamicDirCache::PageSizeInSegs() const
  1.1035 +	{
  1.1036 +	// initialize cache memory manager as all file systems have mounted by now
  1.1037 +	ASSERT(CCacheMemoryManagerFactory::CacheMemoryManager());
  1.1038 +	const TUint32 SegmentSizeInBytesLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2();
  1.1039 +
  1.1040 +	// Page size should be non-zero
  1.1041 +	ASSERT(iPageSizeInBytes);
  1.1042 +
  1.1043 +	TUint32 segs = iPageSizeInBytes >> SegmentSizeInBytesLog2;
  1.1044 +	return segs > 0 ? segs : 1;
  1.1045 +	}
  1.1046 +
  1.1047 +/**
  1.1048 +Deque the page from locked queue or unlocked queue. All pages are managed through these two queues, expect iActive
  1.1049 +page.
  1.1050 +@param	aPage	the pointer of the page to be dequeued
  1.1051 +@return	TInt	KErrArgument if aPage is invalid, otherwise KErrNone.
  1.1052 +*/
  1.1053 +TInt CDynamicDirCache::DeQueue(TDynamicDirCachePage* aPage)
  1.1054 +	{
  1.1055 +	ASSERT(aPage);
  1.1056 +	if (!aPage)
  1.1057 +		return KErrArgument;
  1.1058 +
  1.1059 +	if (aPage->iType == TDynamicDirCachePage::ELocked)
  1.1060 +		{
  1.1061 +		aPage->Deque();
  1.1062 +		aPage->SetPageType(TDynamicDirCachePage::EUnknown);
  1.1063 +		--iLockedQCount;
  1.1064 +		}
  1.1065 +	else if (aPage->iType == TDynamicDirCachePage::EUnlocked)
  1.1066 +		{
  1.1067 +		aPage->Deque();
  1.1068 +		aPage->SetPageType(TDynamicDirCachePage::EUnknown);
  1.1069 +		--iUnlockedQCount;
  1.1070 +		}
  1.1071 +	else
  1.1072 +		{
  1.1073 +		ASSERT(0);
  1.1074 +		return KErrArgument;
  1.1075 +		}
  1.1076 +	return KErrNone;
  1.1077 +	}
  1.1078 +
  1.1079 +/**
  1.1080 +Insert a page to the first position of locked queue or unlocked queue.
  1.1081 +@param	aPage	the pointer of the page to be inserted.
  1.1082 +@param	aType	the type of the queue to be inserted.
  1.1083 +@return	TInt	KErrArgument if aPage is invalid, otherwise KErrNone.
  1.1084 +*/
  1.1085 +TInt CDynamicDirCache::AddFirstOntoQueue(TDynamicDirCachePage* aPage, TDynamicDirCachePage::TPageType aType)
  1.1086 +	{
  1.1087 +	ASSERT(aPage);
  1.1088 +	if (!aPage)
  1.1089 +		return KErrArgument;
  1.1090 +
  1.1091 +	if (aType == TDynamicDirCachePage::ELocked)
  1.1092 +		{
  1.1093 +		iLockedQ.AddFirst(*aPage);
  1.1094 +		aPage->SetPageType(TDynamicDirCachePage::ELocked);
  1.1095 +		++iLockedQCount;
  1.1096 +		}
  1.1097 +	else if (aType == TDynamicDirCachePage::EUnlocked)
  1.1098 +		{
  1.1099 +		iUnlockedQ.AddFirst(*aPage);
  1.1100 +		aPage->SetPageType(TDynamicDirCachePage::EUnlocked);
  1.1101 +		++iUnlockedQCount;
  1.1102 +		}
  1.1103 +	else
  1.1104 +		{
  1.1105 +		ASSERT(0);
  1.1106 +		return KErrArgument;
  1.1107 +		}
  1.1108 +
  1.1109 +	return KErrNone;
  1.1110 +	}
  1.1111 +
  1.1112 +/**
  1.1113 +Remove a page from the lookup table, indexed by the starting media address of the page content.
  1.1114 +@param	aPagePos	the starting media position of the page to be removed.
  1.1115 +*/
  1.1116 +TInt CDynamicDirCache::LookupTblRemove(TInt64 aPagePos)
  1.1117 +	{
  1.1118 +	if (aPagePos == 0)
  1.1119 +		{
  1.1120 +		return KErrNone;
  1.1121 +		}
  1.1122 +
  1.1123 +	TInt r = iLookupTable.Remove(TLookupEntry(aPagePos, 0, NULL));
  1.1124 +	return r;
  1.1125 +	}
  1.1126 +
  1.1127 +/**
  1.1128 +Insert a page to the lookup table, indexed by the starting media address of the page content.
  1.1129 +@param	aPagePos	the starting media position of the page to be inserted.
  1.1130 +*/
  1.1131 +TInt CDynamicDirCache::LookupTblAdd(TDynamicDirCachePage* aPage)
  1.1132 +	{
  1.1133 +	ASSERT(aPage);
  1.1134 +	if (!aPage)
  1.1135 +		return KErrArgument;
  1.1136 +
  1.1137 +	if (aPage->StartPos() == 0)
  1.1138 +		{
  1.1139 +		return KErrNone;
  1.1140 +		}
  1.1141 +
  1.1142 +	TInt r = iLookupTable.Insert(TLookupEntry(aPage->StartPos(), iPageSizeInBytes, aPage));
  1.1143 +	return r;
  1.1144 +	}
  1.1145 +
  1.1146 +/**
  1.1147 +Reset the media address of the page to 0, also invalidate the page.
  1.1148 +@param	aPage	the pointer of the page to be reset.
  1.1149 +*/
  1.1150 +TInt CDynamicDirCache::ResetPagePos(TDynamicDirCachePage* aPage)
  1.1151 +	{
  1.1152 +	ASSERT(aPage);
  1.1153 +	if (!aPage)
  1.1154 +		return KErrArgument;
  1.1155 +
  1.1156 +	aPage->ResetPos();
  1.1157 +	return KErrNone;
  1.1158 +	}
  1.1159 +
  1.1160 +/**
  1.1161 +Search the lookup table to find the page start with a specific media address.
  1.1162 +@param	aPos	the starting media address to be searched.
  1.1163 +*/
  1.1164 +TDynamicDirCachePage* CDynamicDirCache::LookupTblFind(TInt64 aPos)
  1.1165 +	{
  1.1166 +	if (aPos == 0)
  1.1167 +		{
  1.1168 +		ASSERT(0);
  1.1169 +		return NULL;
  1.1170 +		}
  1.1171 +
  1.1172 +	TLookupEntry* entry = iLookupTable.Find(TLookupEntry(aPos, 0, NULL));
  1.1173 +	if(entry)
  1.1174 +		{
  1.1175 +		// last entry on used queue is used as the 'active' page & may not be valid
  1.1176 +		if (!entry->iPage->IsValid())
  1.1177 +			return NULL;
  1.1178 +
  1.1179 +		return entry->iPage;
  1.1180 +		}
  1.1181 +
  1.1182 +	return NULL;
  1.1183 +	}