os/kernelhwsrv/userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// f32\sfat\sl_dir_cache.cpp
sl@0
    15
//
sl@0
    16
//
sl@0
    17
sl@0
    18
#include "sl_std.h"
sl@0
    19
#include "sl_dir_cache.h"
sl@0
    20
sl@0
    21
//======================================================================
sl@0
    22
TDynamicDirCachePage::~TDynamicDirCachePage()
sl@0
    23
	{
sl@0
    24
	}
sl@0
    25
sl@0
    26
/**
sl@0
    27
The static cache page creation function.
sl@0
    28
Cache page objects are not supposed to be created on the stack, so this factory function is required.
sl@0
    29
*/
sl@0
    30
TDynamicDirCachePage* TDynamicDirCachePage::NewL(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
sl@0
    31
	{
sl@0
    32
	return new(ELeave) TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr);
sl@0
    33
	}
sl@0
    34
sl@0
    35
/**
sl@0
    36
Cache page constructor.
sl@0
    37
@param	aOwnerCache	pointer of the cache that owns this page
sl@0
    38
@param	aStartMedPos	the start address on the media that this page caches
sl@0
    39
@param	aStartRamAddr	the start address in the ram that this page content lives
sl@0
    40
*/
sl@0
    41
TDynamicDirCachePage::TDynamicDirCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
sl@0
    42
:iStartMedPos(aStartMedPos),
sl@0
    43
iStartRamAddr(aStartRamAddr),
sl@0
    44
iOwnerCache(aOwnerCache),
sl@0
    45
iValid(EFalse),
sl@0
    46
iLocked(EFalse)
sl@0
    47
	{
sl@0
    48
	//__PRINT3(_L("TDynamicDirCachePage::TDynamicDirCachePage(aStartMedPos=%lx, aStartRamAddr=0x%X, aPageSize=%u)"), aStartMedPos, aStartRamAddr, PageSizeInBytes());
sl@0
    49
	iType = EUnknown;
sl@0
    50
	}
sl@0
    51
sl@0
    52
/////////////////////////////// class CDynamicDirCache::TLookupEntry ///////////////////////////
sl@0
    53
/**
sl@0
    54
Required by RHashSet<TLookupEntry> to identify individual hash set entries.
sl@0
    55
@see	RHashSet
sl@0
    56
*/
sl@0
    57
TBool IdentityFunction(const TLookupEntry& aEntry1, const TLookupEntry& aEntry2)
sl@0
    58
	{
sl@0
    59
	// only check starting med pos for hash searching
sl@0
    60
	return aEntry1.iPos == aEntry2.iPos;
sl@0
    61
	}
sl@0
    62
/**
sl@0
    63
Required by RHashSet<TLookupEntry> to generate hash value.
sl@0
    64
@see	RHashSet
sl@0
    65
*/
sl@0
    66
TUint32 HashFunction(const TLookupEntry& aEntry)
sl@0
    67
	{
sl@0
    68
	return (DefaultHash::Integer(I64HIGH(aEntry.iPos)) + DefaultHash::Integer(I64LOW(aEntry.iPos)));
sl@0
    69
	}
sl@0
    70
sl@0
    71
/////////////////////////////// class CDynamicDirCache ///////////////////////////
sl@0
    72
CDynamicDirCache::~CDynamicDirCache()
sl@0
    73
	{
sl@0
    74
	__PRINT(_L("CDynamicDirCache::~CDynamicDirCache()"));
sl@0
    75
sl@0
    76
	// we should never decommit locked pages
sl@0
    77
    while (!iLockedQ.IsEmpty())
sl@0
    78
		{
sl@0
    79
		TDynamicDirCachePage* page = iLockedQ.Last();
sl@0
    80
		DeQueue(page);		// remove from queue
sl@0
    81
		LookupTblRemove(page->StartPos());	// remove from lookuptable
sl@0
    82
		delete page;
sl@0
    83
		}
sl@0
    84
	ASSERT(iLockedQCount == 0);
sl@0
    85
sl@0
    86
	while (!iUnlockedQ.IsEmpty())
sl@0
    87
		{
sl@0
    88
		TDynamicDirCachePage* page = iUnlockedQ.Last();
sl@0
    89
		DeQueue(page);		// remove from queue
sl@0
    90
		LookupTblRemove(page->StartPos());	// remove from lookuptable
sl@0
    91
		DecommitPage(page);	// inform cache client to decommit page memory
sl@0
    92
		delete page;
sl@0
    93
		}
sl@0
    94
	ASSERT(iUnlockedQCount == 0);
sl@0
    95
sl@0
    96
	ASSERT(iLookupTable.Count() == 0);
sl@0
    97
	iLookupTable.Close();
sl@0
    98
    if (iCacheMemoryClient)
sl@0
    99
    	iCacheMemoryClient->Reset();
sl@0
   100
	}
sl@0
   101
sl@0
   102
/**
sl@0
   103
Constructor of CDynamicDirCache.
sl@0
   104
@param	aDrive	local drive interface to read/write media
sl@0
   105
@param	aMinPageNum	the minimum page number for the cache, includes iActive page and locked pages.
sl@0
   106
@param	aMaxPageNum	the maximum page number for the cache, includes iActive page, locked pages and unlocked pages.
sl@0
   107
@param	aPageSizeInBytesLog2	the log2 value of page size in bytes, assumes page size is always a power of two
sl@0
   108
*/
sl@0
   109
CDynamicDirCache::CDynamicDirCache(TDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeInBytesLog2)
sl@0
   110
:iPageSizeLog2(aPageSizeInBytesLog2),
sl@0
   111
iMinSizeInPages(aMinPageNum),
sl@0
   112
iMaxSizeInPages(aMaxPageNum),
sl@0
   113
iDrive(aDrive),
sl@0
   114
iLockedQ(_FOFF(TDynamicDirCachePage, iLink)),
sl@0
   115
iUnlockedQ(_FOFF(TDynamicDirCachePage, iLink)),
sl@0
   116
iLockedQCount(0),
sl@0
   117
iUnlockedQCount(0),
sl@0
   118
iHashFunction(HashFunction),
sl@0
   119
iIdentityFunction(IdentityFunction),
sl@0
   120
iLookupTable(iHashFunction, iIdentityFunction)
sl@0
   121
	{
sl@0
   122
	iPageSizeInBytes = 1 << aPageSizeInBytesLog2;
sl@0
   123
	iCacheDisabled = EFalse;
sl@0
   124
    iMinCacheSizeInBytes = aMinPageNum << aPageSizeInBytesLog2;
sl@0
   125
    iMaxCacheSizeInBytes = aMaxPageNum << aPageSizeInBytesLog2;
sl@0
   126
    ASSERT(iPageSizeInBytes && iPageSizeInBytes <= iMinCacheSizeInBytes && iMinCacheSizeInBytes <= iMaxCacheSizeInBytes);
sl@0
   127
	// initial value, will be reset from outside
sl@0
   128
	iCacheBasePos = 0;
sl@0
   129
	}
sl@0
   130
sl@0
   131
/**
sl@0
   132
Second phase constructor of CDynamicDirCache.
sl@0
   133
@param	aClientName the identification of cache memeory client this cache connects
sl@0
   134
*/
sl@0
   135
void CDynamicDirCache::ConstructL(const TDesC& aClientName)
sl@0
   136
	{
sl@0
   137
//    __PRINT3(_L("CDynamicDirCache::ConstructL(Min=%u, Max=%u, page=%u)"), iMinCacheSizeInBytes, iMaxCacheSizeInBytes, iPageSizeInBytes);
sl@0
   138
	CCacheMemoryManager* manager = CCacheMemoryManagerFactory::CacheMemoryManager();
sl@0
   139
	if (manager)
sl@0
   140
		{
sl@0
   141
		// client will register itself onto cache memory manager when created
sl@0
   142
		// note this operation may leave under OOM condition
sl@0
   143
		iCacheMemoryClient = manager->ConnectClientL(aClientName, iMinSizeInPages * PageSizeInSegs(), iMaxSizeInPages * PageSizeInSegs());
sl@0
   144
		}
sl@0
   145
	else
sl@0
   146
		{
sl@0
   147
		User::Leave(KErrNotSupported);
sl@0
   148
		}
sl@0
   149
sl@0
   150
	ASSERT(iCacheMemoryClient);
sl@0
   151
	if (!iCacheMemoryClient)
sl@0
   152
		{
sl@0
   153
		User::Leave(KErrNoMemory);
sl@0
   154
		}
sl@0
   155
sl@0
   156
sl@0
   157
	// allocate as many permanently locked pages as there are threads - plus one
sl@0
   158
	// otherwise DoMakePageMRU() won't work properly with only one thread
sl@0
   159
    //-- At present moment the size of TDrive thread pool is 1 (1 drive thread in a pool)
sl@0
   160
	iPermanentlyAllocatedPageCount = 1; 
sl@0
   161
sl@0
   162
	if (iPermanentlyAllocatedPageCount > iMinSizeInPages)
sl@0
   163
		iMinSizeInPages = iPermanentlyAllocatedPageCount;
sl@0
   164
sl@0
   165
	for (TUint n=0; n<iPermanentlyAllocatedPageCount; n++)
sl@0
   166
		{
sl@0
   167
		TDynamicDirCachePage* pPage = AllocateAndLockNewPageL(0);
sl@0
   168
		AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
sl@0
   169
		LookupTblAdd(pPage);
sl@0
   170
		}
sl@0
   171
sl@0
   172
	}
sl@0
   173
sl@0
   174
/**
sl@0
   175
Static factory function of CDynamicDirCache
sl@0
   176
*/
sl@0
   177
CDynamicDirCache* CDynamicDirCache::NewL(TDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeLog2, const TDesC& aClientName)
sl@0
   178
    {
sl@0
   179
    __PRINT3(_L("CDynamicDirCache::NewL(MinPageNum=%u, MaxPageNum=%u, page=%u)"), aMinPageNum, aMaxPageNum, 1<<aPageSizeLog2);
sl@0
   180
    CDynamicDirCache* pSelf = new (ELeave) CDynamicDirCache(aDrive, aMinPageNum, aMaxPageNum, aPageSizeLog2);
sl@0
   181
    CleanupStack::PushL(pSelf);
sl@0
   182
    pSelf->ConstructL(aClientName);
sl@0
   183
    CleanupStack::Pop();
sl@0
   184
    return pSelf;
sl@0
   185
    }
sl@0
   186
sl@0
   187
/**
sl@0
   188
Insert an unlocked page into the last position of the locked queue, may squeeze the original last page into
sl@0
   189
the unlocked queue.
sl@0
   190
This function is used on last visited but 'unlocked' pages to avoid excessive lock/unlock calls to cache memory
sl@0
   191
manager as contiguous entry reading/writing often happens on the same page.
sl@0
   192
@param	aPage	the page to be inserted.
sl@0
   193
@pre	the page type of aPage should only be TDynamicDirCachePage::EUnknown
sl@0
   194
*/
sl@0
   195
void CDynamicDirCache::MakePageLastLocked(TDynamicDirCachePage* aPage)
sl@0
   196
	{
sl@0
   197
	// this function should not be called on active pages
sl@0
   198
	ASSERT(aPage->iType == TDynamicDirCachePage::EUnknown);
sl@0
   199
sl@0
   200
	if (iLockedQ.IsEmpty())
sl@0
   201
		{
sl@0
   202
		// if locked queue is empty, add it onto the locked queue directly
sl@0
   203
		AddFirstOntoQueue(aPage, TDynamicDirCachePage::ELocked);
sl@0
   204
		}
sl@0
   205
	else
sl@0
   206
		{
sl@0
   207
		// otherwise, we squeeze for the last position on locked queue
sl@0
   208
		while (iLockedQCount + 1 >= iMinSizeInPages)
sl@0
   209
			{
sl@0
   210
			TDynamicDirCachePage* last = iLockedQ.Last();
sl@0
   211
			DeQueue(last);
sl@0
   212
			UnlockPage(last);
sl@0
   213
			AddFirstOntoQueue(last, TDynamicDirCachePage::EUnlocked);
sl@0
   214
			}
sl@0
   215
sl@0
   216
		// iLockedQCount + 1 < iMinSizeInPages
sl@0
   217
		iLockedQ.AddLast(*aPage);
sl@0
   218
		aPage->SetPageType(TDynamicDirCachePage::ELocked);
sl@0
   219
		iLockedQCount++;
sl@0
   220
		}
sl@0
   221
	}
sl@0
   222
sl@0
   223
/**
sl@0
   224
    Read data from a single page. If the page is not found or not valid anymore, read media onto iActive page first.
sl@0
   225
    The data will be _Appended_ the the descriptor aDes. The caller is responsible for maintaining this descriptor.
sl@0
   226
sl@0
   227
    @param	aPos	the starting position of the media address to be read.
sl@0
   228
    @param	aLength	the length of the content to be read.
sl@0
   229
    @param	aDes	the descriptor to contain the content.
sl@0
   230
    @pre	aLength should be no more than page size.
sl@0
   231
*/
sl@0
   232
void CDynamicDirCache::ReadDataFromSinglePageL(TInt64 aPos, TInt aLength, TDes8& aDes)
sl@0
   233
	{
sl@0
   234
    //-- the data section is in the cache page entirely, take data directly from the cache
sl@0
   235
	TDynamicDirCachePage* pPage = FindPageByPos(aPos);
sl@0
   236
    if (pPage)
sl@0
   237
    	{
sl@0
   238
		// lock page before reading,
sl@0
   239
    	if (LockPage(pPage) != NULL)
sl@0
   240
    		{
sl@0
   241
    		// read data and append them to the descriptor
sl@0
   242
            aDes.Append(pPage->PtrInPage(aPos), aLength);
sl@0
   243
sl@0
   244
sl@0
   245
            // if page is from unlocked queue, insert it onto the last page of the locked
sl@0
   246
            //  queue. this is to avoid excessive locking and unlocking operations that is
sl@0
   247
            //  highly likely to happen for following reads.
sl@0
   248
            if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
sl@0
   249
            	{
sl@0
   250
            	DeQueue(pPage);
sl@0
   251
            	MakePageLastLocked(pPage);
sl@0
   252
            	}
sl@0
   253
    		}
sl@0
   254
    	else	// page locking failed
sl@0
   255
    		{
sl@0
   256
    		ASSERT(pPage->PageType() == TDynamicDirCachePage::EUnlocked);
sl@0
   257
    		DeQueue(pPage);
sl@0
   258
    		LookupTblRemove(pPage->StartPos());
sl@0
   259
    		DecommitPage(pPage);
sl@0
   260
    		delete pPage;
sl@0
   261
    		pPage = NULL;
sl@0
   262
    		}
sl@0
   263
    	}
sl@0
   264
sl@0
   265
	if (!pPage)
sl@0
   266
		{
sl@0
   267
        // if page not found or page data not valid anymore, use active page to read data in
sl@0
   268
        pPage = UpdateActivePageL(aPos);
sl@0
   269
        // read data and append them to the descriptor
sl@0
   270
        aDes.Append(pPage->PtrInPage(aPos), aLength);
sl@0
   271
    	}
sl@0
   272
sl@0
   273
	}
sl@0
   274
sl@0
   275
//====================================================================
sl@0
   276
/**
sl@0
   277
Implementation of pure virtual function.
sl@0
   278
@see	MWTCacheInterface::ReadL()
sl@0
   279
*/
sl@0
   280
void CDynamicDirCache::ReadL(TInt64 aPos, TInt aLength, TDes8& aDes)
sl@0
   281
	{
sl@0
   282
#ifdef _DEBUG
sl@0
   283
    if(iCacheDisabled)
sl@0
   284
        {
sl@0
   285
        // cache is disabled for debug purposes
sl@0
   286
        __PRINT(_L("CDynamicDirCache disabled"));
sl@0
   287
        User::LeaveIfError(iDrive.ReadNonCritical(aPos, aLength, aDes));
sl@0
   288
        return;
sl@0
   289
        }
sl@0
   290
#endif //_DEBUG
sl@0
   291
sl@0
   292
    aDes.Zero();
sl@0
   293
    const TUint32 PageSz = iPageSizeInBytes;//-- cache page size
sl@0
   294
sl@0
   295
    TInt64 pageStartMedPos = CalcPageStartPos(aPos);
sl@0
   296
    const TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos); //-- number of bytes from aPos to the end of the page
sl@0
   297
sl@0
   298
//    __PRINT5(_L("CDynamicDirCache::ReadL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, aLength, pageStartMedPos, PageSz, bytesToPageEnd);
sl@0
   299
    // if all data needed is on a single page
sl@0
   300
    if((TUint32)aLength <= bytesToPageEnd)
sl@0
   301
        {
sl@0
   302
        ReadDataFromSinglePageL(aPos, aLength, aDes);
sl@0
   303
        }
sl@0
   304
    // or data to be read cross cache page boundary or probably we have more than 1 page to read
sl@0
   305
    else
sl@0
   306
        {
sl@0
   307
        __PRINT(_L("CDynamicDirCache::ReadL() CROSS PAGE!"));
sl@0
   308
        TUint32 dataLen(aLength);   //-- current data length
sl@0
   309
        TInt64  currMediaPos(aPos); //-- current media position
sl@0
   310
sl@0
   311
        //-- 1. read data that are already in the current page
sl@0
   312
        ReadDataFromSinglePageL(currMediaPos, bytesToPageEnd, aDes);
sl@0
   313
        dataLen -= bytesToPageEnd;
sl@0
   314
        currMediaPos += bytesToPageEnd;
sl@0
   315
sl@0
   316
        //-- 2. read whole pages of data
sl@0
   317
        while (dataLen >= PageSz)
sl@0
   318
        	{
sl@0
   319
        	//-- find out if currMediaPos is in cache. If not, find a spare page and read data there
sl@0
   320
            ReadDataFromSinglePageL(currMediaPos, PageSz, aDes);
sl@0
   321
            currMediaPos += PageSz;
sl@0
   322
            dataLen -= PageSz;
sl@0
   323
        	}
sl@0
   324
sl@0
   325
        //-- 3. read the rest of the data
sl@0
   326
        if(dataLen > 0)
sl@0
   327
            {
sl@0
   328
            ReadDataFromSinglePageL(currMediaPos, dataLen, aDes);
sl@0
   329
            }
sl@0
   330
        } //else((TUint32)aLength <= bytesToPageEnd)
sl@0
   331
	}
sl@0
   332
sl@0
   333
/**
sl@0
   334
Write data through a single page. If the page is not found or not valid anymore, read media onto iActive page
sl@0
   335
first, then write data through iActive page.
sl@0
   336
@param	aPos	the starting position of the media address to be write.
sl@0
   337
@param	aData	the starting address that the writing content lives in the ram.
sl@0
   338
@param	aDataLen	the length of the content to be written.
sl@0
   339
@pre	aDataLen	should be no more than page size.
sl@0
   340
*/
sl@0
   341
void CDynamicDirCache::WriteDataOntoSinglePageL(TInt64 aPos, const TUint8* aData, TUint32 aDataLen)
sl@0
   342
	{
sl@0
   343
	ASSERT(aDataLen <= iPageSizeInBytes);
sl@0
   344
    //-- the data section is in the cache page entirely, take data directly from the cache
sl@0
   345
	TDynamicDirCachePage* pPage = FindPageByPos(aPos);
sl@0
   346
    if (pPage)
sl@0
   347
    	{
sl@0
   348
		// lock page before writing,
sl@0
   349
    	if (LockPage(pPage) != NULL)
sl@0
   350
    		{
sl@0
   351
    		//-- update cache
sl@0
   352
            Mem::Copy(pPage->PtrInPage(aPos), aData, aDataLen);
sl@0
   353
    		}
sl@0
   354
    	else
sl@0
   355
    		{
sl@0
   356
    		ASSERT(pPage->PageType() == TDynamicDirCachePage::EUnlocked);
sl@0
   357
    		DeQueue(pPage);
sl@0
   358
    		LookupTblRemove(pPage->StartPos());
sl@0
   359
    		DecommitPage(pPage);
sl@0
   360
    		delete pPage;
sl@0
   361
    		pPage = NULL;
sl@0
   362
    		}
sl@0
   363
    	}
sl@0
   364
sl@0
   365
    // if page not found or page data not valid anymore, use active page to read data in
sl@0
   366
    if (!pPage)
sl@0
   367
    	{
sl@0
   368
        pPage = UpdateActivePageL(aPos);
sl@0
   369
        //-- update cache
sl@0
   370
        Mem::Copy(pPage->PtrInPage(aPos), aData, aDataLen);
sl@0
   371
    	}
sl@0
   372
sl@0
   373
	// make sure the page is unlocked after use
sl@0
   374
	if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
sl@0
   375
		{
sl@0
   376
		UnlockPage(pPage);
sl@0
   377
		}
sl@0
   378
sl@0
   379
	// always make writting events MRU
sl@0
   380
	DoMakePageMRU(aPos);
sl@0
   381
    return;
sl@0
   382
	}
sl@0
   383
sl@0
   384
/**
sl@0
   385
Implementation of pure virtual function.
sl@0
   386
@see	MWTCacheInterface::WriteL()
sl@0
   387
*/
sl@0
   388
void CDynamicDirCache::WriteL(TInt64 aPos,const TDesC8& aDes)
sl@0
   389
	{
sl@0
   390
#ifdef _DEBUG
sl@0
   391
    if(iCacheDisabled)
sl@0
   392
        {
sl@0
   393
        // cache is disabled for debug purposes
sl@0
   394
        __PRINT(_L("CDynamicDirCache disabled"));
sl@0
   395
        User::LeaveIfError(iDrive.WriteCritical(aPos,aDes));
sl@0
   396
        return;
sl@0
   397
        }
sl@0
   398
#endif //_DEBUG
sl@0
   399
sl@0
   400
    TUint32 dataLen = aDes.Size();
sl@0
   401
    const TUint8* pData   = aDes.Ptr();
sl@0
   402
    const TUint32 PageSz  = iPageSizeInBytes; //-- cache page size
sl@0
   403
sl@0
   404
    TInt64 pageStartMedPos = CalcPageStartPos(aPos);
sl@0
   405
    TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos);
sl@0
   406
sl@0
   407
//    __PRINT5(_L("CDynamicDirCache::WriteL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, dataLen, pageStartMedPos, PageSz, bytesToPageEnd);
sl@0
   408
sl@0
   409
    if(dataLen <= bytesToPageEnd)
sl@0
   410
        {
sl@0
   411
        WriteDataOntoSinglePageL(aPos, pData, dataLen);
sl@0
   412
        }
sl@0
   413
    else
sl@0
   414
        {
sl@0
   415
        __PRINT(_L("CDynamicDirCache::WriteL() CROSS PAGE!"));
sl@0
   416
sl@0
   417
        //-- Data to be written cross cache page boundary or probably we have more than 1 page to write
sl@0
   418
        TInt64  currMediaPos(aPos);
sl@0
   419
sl@0
   420
        //-- 1. update the current page
sl@0
   421
        WriteDataOntoSinglePageL(currMediaPos, pData, bytesToPageEnd);
sl@0
   422
sl@0
   423
        pData += bytesToPageEnd;
sl@0
   424
        currMediaPos += bytesToPageEnd;
sl@0
   425
        dataLen -= bytesToPageEnd;
sl@0
   426
sl@0
   427
        //-- 2. write whole pages of data to the cache
sl@0
   428
        while (dataLen >= PageSz)
sl@0
   429
        	{
sl@0
   430
            WriteDataOntoSinglePageL(currMediaPos, pData, PageSz);
sl@0
   431
sl@0
   432
            pData += PageSz;
sl@0
   433
            currMediaPos += PageSz;
sl@0
   434
            dataLen -= PageSz;
sl@0
   435
        	}
sl@0
   436
sl@0
   437
        //-- 3. write the rest of the data
sl@0
   438
        if(dataLen > 0)
sl@0
   439
            {
sl@0
   440
            WriteDataOntoSinglePageL(currMediaPos, pData, dataLen);
sl@0
   441
            }
sl@0
   442
        }// else(dataLen <= bytesToPageEnd)
sl@0
   443
sl@0
   444
sl@0
   445
    //-- write data to the media
sl@0
   446
    const TInt nErr = iDrive.WriteCritical(aPos,aDes);
sl@0
   447
    if(nErr != KErrNone)
sl@0
   448
        {//-- some serious problem occured during writing, invalidate cache.
sl@0
   449
        InvalidateCache();
sl@0
   450
        User::Leave(nErr);
sl@0
   451
        }
sl@0
   452
	}
sl@0
   453
sl@0
   454
/**
sl@0
   455
    Invalidate the cache
sl@0
   456
    @see	MWTCacheInterface::InvalidateCache()
sl@0
   457
*/
sl@0
   458
void CDynamicDirCache::DoInvalidateCache(void)
sl@0
   459
	{
sl@0
   460
	__PRINT2(_L("CDynamicDirCache::InvalidateCache(locked=%d, unlocked=%d)"), iLockedQCount, iUnlockedQCount);
sl@0
   461
	// we should never decommit locked pages as they needs to be reserved anyway
sl@0
   462
	// the overhead of unnecessary page committing operations
sl@0
   463
sl@0
   464
	TInt pagesToRemoveFromLockedQueue = iLockedQCount - iPermanentlyAllocatedPageCount;
sl@0
   465
	TInt n;
sl@0
   466
	for (n=0; n<pagesToRemoveFromLockedQueue; n++)
sl@0
   467
		{
sl@0
   468
		TDynamicDirCachePage* page = iLockedQ.Last();
sl@0
   469
		DeQueue(page);						// remove from queue
sl@0
   470
		LookupTblRemove(page->StartPos());	// remove from lookuptable
sl@0
   471
		DecommitPage(page);					// inform cache client to decommit page memory
sl@0
   472
		delete page;
sl@0
   473
		}
sl@0
   474
	ASSERT(iLockedQCount == iPermanentlyAllocatedPageCount);
sl@0
   475
sl@0
   476
	TDblQueIter<TDynamicDirCachePage> q(iLockedQ);
sl@0
   477
	q.SetToFirst();
sl@0
   478
	while((TDynamicDirCachePage*) q)
sl@0
   479
		{
sl@0
   480
		TDynamicDirCachePage* page = q++;
sl@0
   481
		LookupTblRemove(page->StartPos());// remove from lookuptable
sl@0
   482
		ResetPagePos(page);				// reset start media position (0), invalidate page content
sl@0
   483
		}
sl@0
   484
sl@0
   485
	// however we should decommit unlocked pages here
sl@0
   486
	while (!iUnlockedQ.IsEmpty())
sl@0
   487
		{
sl@0
   488
		TDynamicDirCachePage* page = iUnlockedQ.Last();
sl@0
   489
		DeQueue(page);						// remove from queue
sl@0
   490
		LookupTblRemove(page->StartPos());	// remove from lookuptable
sl@0
   491
		DecommitPage(page);					// inform cache client to decommit page memory
sl@0
   492
		delete page;
sl@0
   493
		}
sl@0
   494
	ASSERT(iUnlockedQCount == 0);
sl@0
   495
sl@0
   496
	ASSERT(iLockedQCount == iPermanentlyAllocatedPageCount);
sl@0
   497
sl@0
   498
	ASSERT(iCacheMemoryClient);
sl@0
   499
	}
sl@0
   500
sl@0
   501
/**
sl@0
   502
Implementation of pure virtual function.
sl@0
   503
@see	MWTCacheInterface::InvalidateCache()
sl@0
   504
*/
sl@0
   505
void CDynamicDirCache::InvalidateCache(void)
sl@0
   506
	{
sl@0
   507
	DoInvalidateCache();
sl@0
   508
	}
sl@0
   509
sl@0
   510
/** this method isn't implemented*/
sl@0
   511
void CDynamicDirCache::InvalidateCachePage(TUint64 /*aPos*/)
sl@0
   512
    {
sl@0
   513
    ASSERT(0);
sl@0
   514
    }
sl@0
   515
sl@0
   516
sl@0
   517
/**
sl@0
   518
Implementation of pure virtual function.
sl@0
   519
@see	MWTCacheInterface::PosCached()
sl@0
   520
*/
sl@0
   521
TUint32 CDynamicDirCache::PosCached(const TInt64& aPos, TInt64& aCachedPosStart)
sl@0
   522
	{
sl@0
   523
	const TInt64 pageStartMedPos = CalcPageStartPos(aPos);
sl@0
   524
sl@0
   525
	// only search the page in lookup table
sl@0
   526
	// NOTE: we don't count the active page into acount here,
sl@0
   527
	// this is to avoid pulling next pages recursively
sl@0
   528
	TDynamicDirCachePage* pPage = LookupTblFind(pageStartMedPos);
sl@0
   529
sl@0
   530
	// then check if page is still valid if page is on Unlocked Page Queue
sl@0
   531
	if (pPage && pPage->PageType() == TDynamicDirCachePage::EUnlocked)
sl@0
   532
		{
sl@0
   533
		if (LockPage(pPage) != NULL)
sl@0
   534
			{
sl@0
   535
//			__PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) found on Unlocked Queue!"), aPos);
sl@0
   536
			// have to unlock it before returning, otherwise there will be memory leak
sl@0
   537
			UnlockPage(pPage);
sl@0
   538
    	    aCachedPosStart = pPage->StartPos();
sl@0
   539
			return pPage->PageSizeInBytes();
sl@0
   540
			}
sl@0
   541
		else	// if the unlocked page is not valid anymore, remove it
sl@0
   542
			{
sl@0
   543
    		DeQueue(pPage);
sl@0
   544
    		LookupTblRemove(pPage->StartPos());
sl@0
   545
    		DecommitPage(pPage);
sl@0
   546
    		delete pPage;
sl@0
   547
    		pPage = NULL;
sl@0
   548
			}
sl@0
   549
		}
sl@0
   550
	// otherwise if page is already locked or valid active page
sl@0
   551
	else if (pPage)
sl@0
   552
		{
sl@0
   553
		__PRINT1(_L("CDynamicDirCache::PosCached: page(0x%lx) on Locked Queue!"), aPos);
sl@0
   554
	    aCachedPosStart = pPage->StartPos();
sl@0
   555
		return pPage->PageSizeInBytes();
sl@0
   556
		}
sl@0
   557
sl@0
   558
	// page is not found or not valid anymore
sl@0
   559
	return 0;
sl@0
   560
	}
sl@0
   561
sl@0
   562
/**
sl@0
   563
Implementation of pure virtual function.
sl@0
   564
@see	MWTCacheInterface::CacheSizeInBytes()
sl@0
   565
*/
sl@0
   566
TUint32 CDynamicDirCache::CacheSizeInBytes()  const
sl@0
   567
	{
sl@0
   568
	return iMaxCacheSizeInBytes;
sl@0
   569
	}
sl@0
   570
sl@0
   571
/**
sl@0
   572
Implementation of pure virtual function.
sl@0
   573
@see	MWTCacheInterface::Control()
sl@0
   574
*/
sl@0
   575
TInt CDynamicDirCache::Control(TUint32 aFunction, TUint32 aParam1, TAny* aParam2)
sl@0
   576
	{
sl@0
   577
    TInt r = KErrNotSupported;
sl@0
   578
#ifdef _DEBUG
sl@0
   579
    (void)aParam2;
sl@0
   580
    switch(aFunction)
sl@0
   581
        {
sl@0
   582
        // disable / enable cache, for debug
sl@0
   583
        // if aParam1 != 0 cache will be disabled, enabled otherwise
sl@0
   584
        case EDisableCache:
sl@0
   585
            iCacheDisabled = aParam1 ? 1 : 0;
sl@0
   586
            r = KErrNone;
sl@0
   587
        break;
sl@0
   588
sl@0
   589
        // dump cache, for debug
sl@0
   590
        case EDumpCache:
sl@0
   591
        	{
sl@0
   592
        	RFs fs;
sl@0
   593
        	fs.Connect();
sl@0
   594
        	const TUint32 debugRegister = DebugRegister();
sl@0
   595
        	fs.SetDebugRegister(debugRegister|KFSYS);
sl@0
   596
        	Dump();
sl@0
   597
        	fs.SetDebugRegister(debugRegister);
sl@0
   598
        	fs.Close();
sl@0
   599
        	break;
sl@0
   600
        	}
sl@0
   601
        case ECacheInfo:
sl@0
   602
        	{
sl@0
   603
        	RFs fs;
sl@0
   604
        	fs.Connect();
sl@0
   605
        	const TUint32 debugRegister = DebugRegister();
sl@0
   606
        	fs.SetDebugRegister(debugRegister|KFSYS);
sl@0
   607
        	Info();
sl@0
   608
        	fs.SetDebugRegister(debugRegister);
sl@0
   609
        	fs.Close();
sl@0
   610
        	break;
sl@0
   611
        	}
sl@0
   612
sl@0
   613
        default:
sl@0
   614
            __PRINT1(_L("CDynamicDirCache::Control() invalid function: %d"), aFunction);
sl@0
   615
            ASSERT(0);
sl@0
   616
        break;
sl@0
   617
        }
sl@0
   618
sl@0
   619
#else
sl@0
   620
    (void)aFunction; //-- supress warnings
sl@0
   621
    (void)aParam1;
sl@0
   622
    (void)aParam2;
sl@0
   623
    User::Invariant(); //-- don't call this method in release build
sl@0
   624
#endif //_DEBUG
sl@0
   625
sl@0
   626
    return r;
sl@0
   627
	}
sl@0
   628
sl@0
   629
/**
sl@0
   630
Implementation of pure virtual function.
sl@0
   631
@see	MWTCacheInterface::SetCacheBasePos()
sl@0
   632
*/
sl@0
   633
void CDynamicDirCache::SetCacheBasePos(TInt64 aBasePos)
sl@0
   634
	{
sl@0
   635
	iCacheBasePos = aBasePos;
sl@0
   636
	}
sl@0
   637
sl@0
   638
/**
sl@0
   639
Implementation of pure virtual function.
sl@0
   640
@see	MWTCacheInterface::SetCacheBasePos()
sl@0
   641
*/
sl@0
   642
TUint32 CDynamicDirCache::PageSizeInBytesLog2() const
sl@0
   643
	{
sl@0
   644
	return iPageSizeLog2;
sl@0
   645
	}
sl@0
   646
sl@0
   647
sl@0
   648
void CDynamicDirCache::DoMakePageMRU(TInt64 aPos)
sl@0
   649
	{
sl@0
   650
//	__PRINT1(_L("MakePageMRU (%lx)"), aPos);
sl@0
   651
//	__PRINT4(_L("Current Cache State: iLockedQCount=%d, iUnlockedQCount=%d, iLookupTbl=%d, iMaxSizeInPages=%d"), iLockedQCount, iUnlockedQCount, iLookupTable.Count(), iMaxSizeInPages);
sl@0
   652
	// check the MRU page first, if it is already the MRU page, we can return immediately
sl@0
   653
	TInt64 pageStartMedPos = CalcPageStartPos(aPos);
sl@0
   654
	if (!iLockedQ.IsEmpty())
sl@0
   655
		{
sl@0
   656
		if (iLockedQ.First()->StartPos() == pageStartMedPos)
sl@0
   657
			{
sl@0
   658
			return;
sl@0
   659
			}
sl@0
   660
		}
sl@0
   661
sl@0
   662
	TDynamicDirCachePage* pPage = FindPageByPos(aPos);
sl@0
   663
    if (pPage)
sl@0
   664
    	{
sl@0
   665
    	ASSERT(pPage->IsValid());
sl@0
   666
		// lock page before make it MRU
sl@0
   667
    	if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
sl@0
   668
    		{
sl@0
   669
    		ASSERT(!pPage->IsLocked());
sl@0
   670
        	if (LockPage(pPage) == NULL)
sl@0
   671
        		{
sl@0
   672
        		DeQueue(pPage);
sl@0
   673
        		LookupTblRemove(pPage->StartPos());
sl@0
   674
        		DecommitPage(pPage);
sl@0
   675
        		delete pPage;
sl@0
   676
        		pPage = NULL;
sl@0
   677
        		}
sl@0
   678
    		}
sl@0
   679
    	else
sl@0
   680
    		{
sl@0
   681
    		// error checking: page should either be locked or active
sl@0
   682
    		ASSERT(LockPage(pPage) != NULL);
sl@0
   683
    		}
sl@0
   684
    	}
sl@0
   685
sl@0
   686
    // if page not found or page data not valid anymore, use active page to read data
sl@0
   687
    if (!pPage)
sl@0
   688
    	{
sl@0
   689
        TRAPD(err, pPage = UpdateActivePageL(aPos));
sl@0
   690
        if (err != KErrNone)
sl@0
   691
        	{
sl@0
   692
        	// problem occurred reading active page, return immediately.
sl@0
   693
        	return;
sl@0
   694
        	}
sl@0
   695
    	}
sl@0
   696
sl@0
   697
    // by now, the page is either locked or active page
sl@0
   698
	ASSERT(pPage && pPage->IsValid() && pPage->IsLocked());
sl@0
   699
sl@0
   700
sl@0
   701
sl@0
   702
	TBool allocateNewPage = pPage == iLockedQ.Last() && !CacheIsFull();
sl@0
   703
sl@0
   704
sl@0
   705
	switch (pPage->PageType())
sl@0
   706
		{
sl@0
   707
		case TDynamicDirCachePage::EUnlocked:
sl@0
   708
			{
sl@0
   709
			// if page was originally on Unlocked Page Queque, remove it from Unlocked Page Queue, add it
sl@0
   710
			// to the Locked Page Queue and make it MRU
sl@0
   711
			DeQueue(pPage);
sl@0
   712
			AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
sl@0
   713
			// check cache limit
sl@0
   714
			CheckThresholds();
sl@0
   715
			}
sl@0
   716
		case TDynamicDirCachePage::ELocked:
sl@0
   717
			{
sl@0
   718
			// otherwise the page was on Locked Page Queue, make it MRU
sl@0
   719
			// no need to check cache limit
sl@0
   720
			if (pPage != iLockedQ.First())
sl@0
   721
				{
sl@0
   722
				DeQueue(pPage);
sl@0
   723
				AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
sl@0
   724
				}
sl@0
   725
			break;
sl@0
   726
			}
sl@0
   727
		default:
sl@0
   728
			ASSERT(0);
sl@0
   729
		}
sl@0
   730
sl@0
   731
	if (allocateNewPage)
sl@0
   732
		{
sl@0
   733
		TDynamicDirCachePage* nPage = NULL;
sl@0
   734
		TRAPD(err, nPage = AllocateAndLockNewPageL(0));
sl@0
   735
		if (err == KErrNone)
sl@0
   736
			{
sl@0
   737
sl@0
   738
			// about to add a page to end of locked queue, so lie about iLockedQCount
sl@0
   739
			iLockedQCount++;
sl@0
   740
			CheckThresholds();
sl@0
   741
			iLockedQCount--;
sl@0
   742
sl@0
   743
			iLockedQ.AddLast(*nPage);
sl@0
   744
			nPage->SetPageType(TDynamicDirCachePage::ELocked);
sl@0
   745
			++iLockedQCount;
sl@0
   746
			LookupTblAdd(nPage);
sl@0
   747
			}
sl@0
   748
		}
sl@0
   749
	}
sl@0
   750
sl@0
   751
/**
sl@0
   752
    Implementation of pure virtual function.
sl@0
   753
    @see	MDiskSpecialAccessor::MakePageMRU()
sl@0
   754
*/
sl@0
   755
void CDynamicDirCache::MakePageMRU(TInt64 aPos)
sl@0
   756
	{
sl@0
   757
	DoMakePageMRU(aPos);
sl@0
   758
	}
sl@0
   759
sl@0
   760
//====================================================================
sl@0
   761
/**
sl@0
   762
Internal query function, to check if aPos is cached or not. iActive page is included in searching.
sl@0
   763
*/
sl@0
   764
TDynamicDirCachePage* CDynamicDirCache::FindPageByPos(TInt64 aPos)
sl@0
   765
	{
sl@0
   766
//	__PRINT1(_L("CDynamicDirCache::FindPageByPos(aPos=%lx)"), aPos);
sl@0
   767
    // align the page position
sl@0
   768
	TInt64 pageStartMedPos = CalcPageStartPos(aPos);
sl@0
   769
sl@0
   770
	// search in lookup table
sl@0
   771
	return LookupTblFind(pageStartMedPos);
sl@0
   772
	}
sl@0
   773
sl@0
   774
/**
sl@0
   775
read a page length data into iActive page and return iActive page if read is successful.
sl@0
   776
*/
sl@0
   777
TDynamicDirCachePage* CDynamicDirCache::UpdateActivePageL(TInt64 aPos)
sl@0
   778
	{
sl@0
   779
    // align the page position
sl@0
   780
	TInt64 pageStartMedPos = CalcPageStartPos(aPos);
sl@0
   781
sl@0
   782
	ASSERT(!iLockedQ.IsEmpty());
sl@0
   783
	TDynamicDirCachePage* activePage = iLockedQ.Last();
sl@0
   784
sl@0
   785
	if (activePage->StartPos() == pageStartMedPos && activePage->IsValid())
sl@0
   786
		{
sl@0
   787
		return activePage;
sl@0
   788
		}
sl@0
   789
sl@0
   790
	__PRINT2(_L("CDynamicDirCache::UpdateActivePageL(aPos=%lx, active=%lx)"), aPos, activePage->StartPos());
sl@0
   791
sl@0
   792
	activePage->Deque();
sl@0
   793
	LookupTblRemove(activePage->StartPos());
sl@0
   794
sl@0
   795
	// set start med pos value, no other effects, only available to active page
sl@0
   796
	activePage->SetPos(pageStartMedPos);
sl@0
   797
sl@0
   798
	// read data, make active page valid
sl@0
   799
	TUint8* data = activePage->PtrInPage(activePage->iStartMedPos);
sl@0
   800
    TPtr8 dataPtr(data, iPageSizeInBytes);
sl@0
   801
	
sl@0
   802
    const TInt nErr = iDrive.ReadNonCritical(activePage->iStartMedPos, iPageSizeInBytes, dataPtr);
sl@0
   803
sl@0
   804
	iLockedQ.AddLast(*activePage);
sl@0
   805
	LookupTblAdd(activePage);
sl@0
   806
sl@0
   807
    if(nErr !=KErrNone)
sl@0
   808
        {
sl@0
   809
        // some serious problem occured during reading, invalidate cache.
sl@0
   810
        DoInvalidateCache();
sl@0
   811
        User::Leave(nErr);
sl@0
   812
        }
sl@0
   813
    activePage->SetValid(ETrue);
sl@0
   814
sl@0
   815
    return activePage;
sl@0
   816
	}
sl@0
   817
sl@0
   818
/**
sl@0
   819
Check if the number of (locked pages + iActive page) and unlocked pages have exceeded minimum allowed page
sl@0
   820
number and maximum allowed page number respectively.
sl@0
   821
*/
sl@0
   822
void CDynamicDirCache::CheckThresholds()
sl@0
   823
	{
sl@0
   824
	while (iLockedQCount + 1 > iMinSizeInPages)
sl@0
   825
		{
sl@0
   826
		TDynamicDirCachePage* movePage = iLockedQ.Last();
sl@0
   827
		UnlockPage(movePage);
sl@0
   828
		DeQueue(movePage);
sl@0
   829
		TInt err = LookupTblRemove(movePage->StartPos());
sl@0
   830
		ASSERT(err == KErrNone);
sl@0
   831
sl@0
   832
		// if it is a valid page, add onto unlocked queue
sl@0
   833
		if (movePage->StartPos() != 0)
sl@0
   834
			{
sl@0
   835
			ASSERT(movePage->IsValid());
sl@0
   836
			AddFirstOntoQueue(movePage, TDynamicDirCachePage::EUnlocked);
sl@0
   837
			err = LookupTblAdd(movePage);
sl@0
   838
			ASSERT(err == KErrNone);
sl@0
   839
			}
sl@0
   840
		else // reserved page, delete
sl@0
   841
			{
sl@0
   842
			DecommitPage(movePage);
sl@0
   843
			delete movePage;
sl@0
   844
			}
sl@0
   845
		}
sl@0
   846
sl@0
   847
	// if unlocked queue exceeds limit, delete LRU page
sl@0
   848
	// note: all pages on unlocked queue should be valid
sl@0
   849
	while (iUnlockedQCount > iMaxSizeInPages - iMinSizeInPages)
sl@0
   850
		{
sl@0
   851
		TDynamicDirCachePage* removePage = iUnlockedQ.Last();
sl@0
   852
		ASSERT(removePage->StartPos() != 0 && removePage->IsValid());
sl@0
   853
		DeQueue(removePage);
sl@0
   854
		LookupTblRemove(removePage->StartPos());
sl@0
   855
		DecommitPage(removePage);
sl@0
   856
		delete removePage;
sl@0
   857
		}
sl@0
   858
	}
sl@0
   859
sl@0
   860
/**
sl@0
   861
Try to create a new page and lock the page content when it is created. This function should only be called
sl@0
   862
when creating iActive page or making a page MRU (which might result in page evictions).
sl@0
   863
@return	the pointer of the newly created page, or NULL if allocation failed.
sl@0
   864
@param	aStartMedPos	the starting media address of the page to be created.
sl@0
   865
@pre	aStartMedPos should not already be existing in the cache.
sl@0
   866
*/
sl@0
   867
TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPageL(TInt64 aStartMedPos)
sl@0
   868
	{
sl@0
   869
	__PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPageL(aStartMedPos=%lx)"), aStartMedPos);
sl@0
   870
sl@0
   871
	TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs());
sl@0
   872
	if (startRamAddr)
sl@0
   873
		{
sl@0
   874
		// create new page and return
sl@0
   875
		TDynamicDirCachePage* pPage = TDynamicDirCachePage::NewL(this, aStartMedPos, startRamAddr);
sl@0
   876
		pPage->SetLocked(ETrue);
sl@0
   877
		pPage->SetValid(EFalse);
sl@0
   878
		return pPage;
sl@0
   879
		}
sl@0
   880
sl@0
   881
	return NULL;
sl@0
   882
	}
sl@0
   883
sl@0
   884
#ifdef _DEBUG
sl@0
   885
/**
sl@0
   886
Dump cache information, only enabled in debug mode.
sl@0
   887
@see CDynamicDirCache::Control()
sl@0
   888
*/
sl@0
   889
void CDynamicDirCache::Info() const
sl@0
   890
	{
sl@0
   891
	__PRINT(_L("======== CDynamicDirCache::Info ========="));
sl@0
   892
	const TUint32 SegmentSizeInBytesLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2();
sl@0
   893
	// page size
sl@0
   894
	__PRINT1(_L("=== Pages size:               [%d Bytes]"), iPageSizeInBytes);
sl@0
   895
	__PRINT1(_L("=== Segment size:             [%d Bytes]"), 1 << SegmentSizeInBytesLog2);
sl@0
   896
sl@0
   897
	// data size:
sl@0
   898
	__PRINT1(_L("=== Min data size:            [%d Bytes]"), iMinSizeInPages << iPageSizeLog2);
sl@0
   899
	__PRINT1(_L("=== Max data size:            [%d Bytes]"), iMaxSizeInPages << iPageSizeLog2);
sl@0
   900
sl@0
   901
	// memory size:
sl@0
   902
	const TUint32 pageMemSizeLog2 = iPageSizeLog2 > SegmentSizeInBytesLog2 ? iPageSizeLog2 : SegmentSizeInBytesLog2;
sl@0
   903
	__PRINT1(_L("=== Min memory size:          [%d Bytes]"), iMinSizeInPages << pageMemSizeLog2);
sl@0
   904
	__PRINT1(_L("=== Max memory size:          [%d Bytes]"), iMaxSizeInPages << pageMemSizeLog2);
sl@0
   905
sl@0
   906
	// reserved pages
sl@0
   907
	__PRINT1(_L("=== Number of pages reserved: [%d]"), iMinSizeInPages);
sl@0
   908
	__PRINT1(_L("=== Reserved memory:          [%d Bytes]"), (iMinSizeInPages * PageSizeInSegs()) << SegmentSizeInBytesLog2);
sl@0
   909
	// locked page num
sl@0
   910
	__PRINT1(_L("=== Number of pages locked:   [%d]"), iLockedQCount);
sl@0
   911
	__PRINT1(_L("=== Locked memory:            [%d Bytes]"), (iLockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2);
sl@0
   912
	// unlocked page num
sl@0
   913
	__PRINT1(_L("=== Number of pages unlocked: [%d]"), iUnlockedQCount);
sl@0
   914
	__PRINT1(_L("=== Unlocked memory:          [%d Bytes]"), (iUnlockedQCount * PageSizeInSegs()) << SegmentSizeInBytesLog2);
sl@0
   915
	}
sl@0
   916
sl@0
   917
/**
sl@0
   918
Dump cache content, only enabled in debug mode.
sl@0
   919
@see CDynamicDirCache::Control()
sl@0
   920
*/
sl@0
   921
void CDynamicDirCache::Dump()
sl@0
   922
	{
sl@0
   923
	__PRINT(_L("======== CDynamicDirCache::Dump ========="));
sl@0
   924
	if (!iLockedQ.IsEmpty())
sl@0
   925
		{
sl@0
   926
		TDblQueIter<TDynamicDirCachePage> q(iLockedQ);
sl@0
   927
		q.SetToFirst();
sl@0
   928
		TInt i = 0;
sl@0
   929
		while((TDynamicDirCachePage*)q)
sl@0
   930
			{
sl@0
   931
			TDynamicDirCachePage* pP = q++;
sl@0
   932
			__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
   933
			}
sl@0
   934
		}
sl@0
   935
	if (!iUnlockedQ.IsEmpty())
sl@0
   936
		{
sl@0
   937
		TDblQueIter<TDynamicDirCachePage> q(iUnlockedQ);
sl@0
   938
		q.SetToFirst();
sl@0
   939
		TInt i = 0;
sl@0
   940
		while((TDynamicDirCachePage*)q)
sl@0
   941
			{
sl@0
   942
			TDynamicDirCachePage* pP = q++;
sl@0
   943
			__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
   944
			}
sl@0
   945
		}
sl@0
   946
sl@0
   947
	if (iLookupTable.Count())
sl@0
   948
		{
sl@0
   949
		TInt i = 0;
sl@0
   950
		THashSetIter<TLookupEntry> iter(iLookupTable);
sl@0
   951
		TLookupEntry* pEntry;
sl@0
   952
		pEntry = (TLookupEntry*) iter.Next();
sl@0
   953
		while(pEntry)
sl@0
   954
			{
sl@0
   955
			TDynamicDirCachePage* pP = pEntry->iPage;
sl@0
   956
			__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
   957
			pEntry = (TLookupEntry*) iter.Next();
sl@0
   958
			};
sl@0
   959
		}
sl@0
   960
	__PRINT(_L("===========================================\n"));
sl@0
   961
	}
sl@0
   962
#endif //_DEBUG
sl@0
   963
sl@0
   964
/**
sl@0
   965
Lock an unlocked page, or do nothing if the page is already locked.
sl@0
   966
@return	TUint8*	pointer of the page to be locked, if locking is successful, otherwise return NULL.
sl@0
   967
@param	aPage	the pointer of the page to be locked.
sl@0
   968
*/
sl@0
   969
TUint8* CDynamicDirCache::LockPage(TDynamicDirCachePage* aPage)
sl@0
   970
	{
sl@0
   971
	ASSERT(aPage != NULL);
sl@0
   972
	if (aPage->IsLocked())
sl@0
   973
		return aPage->StartPtr();
sl@0
   974
sl@0
   975
	TInt r = iCacheMemoryClient->LockSegments(aPage->StartPtr(), PageSizeInSegs());
sl@0
   976
	if (r == KErrNone)
sl@0
   977
		{
sl@0
   978
		aPage->SetLocked(ETrue);
sl@0
   979
		return aPage->StartPtr();
sl@0
   980
		}
sl@0
   981
sl@0
   982
	return NULL;
sl@0
   983
	}
sl@0
   984
sl@0
   985
/**
sl@0
   986
Unlock a locked page.
sl@0
   987
@return	TInt	KErrNone if unlocking was successful, otherwise system-wide error code.
sl@0
   988
@param	aPage	the pointer of the page to be unlocked.
sl@0
   989
*/
sl@0
   990
TInt CDynamicDirCache::UnlockPage(TDynamicDirCachePage* aPage)
sl@0
   991
	{
sl@0
   992
	ASSERT(aPage != NULL);
sl@0
   993
	__PRINT1(_L("CDynamicDirCache::UnlockPage(%lx)"), aPage->StartPos());
sl@0
   994
	TInt r = iCacheMemoryClient->UnlockSegments(aPage->StartPtr(), PageSizeInSegs());
sl@0
   995
	if (r == KErrNone)
sl@0
   996
		{
sl@0
   997
		aPage->SetLocked(EFalse);
sl@0
   998
		}
sl@0
   999
	return r;
sl@0
  1000
	}
sl@0
  1001
sl@0
  1002
/**
sl@0
  1003
Decommit a locked or unlocked page.
sl@0
  1004
@return	TInt	KErrNone if decommition was successful, otherwise system-wide error code.
sl@0
  1005
@param	aPage	the pointer of the page to be decommitted.
sl@0
  1006
*/
sl@0
  1007
TInt CDynamicDirCache::DecommitPage(TDynamicDirCachePage* aPage)
sl@0
  1008
	{
sl@0
  1009
	ASSERT(aPage != NULL);
sl@0
  1010
	__PRINT1(_L("CDynamicDirCache::DecommitPage(%lx)"), aPage->StartPos());
sl@0
  1011
	if (aPage)
sl@0
  1012
		{
sl@0
  1013
		TInt r = iCacheMemoryClient->DecommitSegments(aPage->StartPtr(), PageSizeInSegs());
sl@0
  1014
		if (r == KErrNone)
sl@0
  1015
			{
sl@0
  1016
			aPage->SetLocked(EFalse);
sl@0
  1017
			aPage->SetValid(EFalse);
sl@0
  1018
			}
sl@0
  1019
		return r;
sl@0
  1020
		}
sl@0
  1021
	return KErrArgument;
sl@0
  1022
	}
sl@0
  1023
sl@0
  1024
/////////////////////////// aluxiliary functions //////////////////////////////////
sl@0
  1025
/**
sl@0
  1026
Calculate the page size in segments. Segment size is the size of the kernel memory unit that cache memory manager manages.
sl@0
  1027
We are making assumption here about the page size: page size should always be either less than segment size
sl@0
  1028
or multiple times of segment size
sl@0
  1029
@return	TUint32	the page size in segments.
sl@0
  1030
*/
sl@0
  1031
TUint32 CDynamicDirCache::PageSizeInSegs() const
sl@0
  1032
	{
sl@0
  1033
	// initialize cache memory manager as all file systems have mounted by now
sl@0
  1034
	ASSERT(CCacheMemoryManagerFactory::CacheMemoryManager());
sl@0
  1035
	const TUint32 SegmentSizeInBytesLog2 = CCacheMemoryManagerFactory::CacheMemoryManager()->SegmentSizeInBytesLog2();
sl@0
  1036
sl@0
  1037
	// Page size should be non-zero
sl@0
  1038
	ASSERT(iPageSizeInBytes);
sl@0
  1039
sl@0
  1040
	TUint32 segs = iPageSizeInBytes >> SegmentSizeInBytesLog2;
sl@0
  1041
	return segs > 0 ? segs : 1;
sl@0
  1042
	}
sl@0
  1043
sl@0
  1044
/**
sl@0
  1045
Deque the page from locked queue or unlocked queue. All pages are managed through these two queues, expect iActive
sl@0
  1046
page.
sl@0
  1047
@param	aPage	the pointer of the page to be dequeued
sl@0
  1048
@return	TInt	KErrArgument if aPage is invalid, otherwise KErrNone.
sl@0
  1049
*/
sl@0
  1050
TInt CDynamicDirCache::DeQueue(TDynamicDirCachePage* aPage)
sl@0
  1051
	{
sl@0
  1052
	ASSERT(aPage);
sl@0
  1053
	if (!aPage)
sl@0
  1054
		return KErrArgument;
sl@0
  1055
sl@0
  1056
	if (aPage->iType == TDynamicDirCachePage::ELocked)
sl@0
  1057
		{
sl@0
  1058
		aPage->Deque();
sl@0
  1059
		aPage->SetPageType(TDynamicDirCachePage::EUnknown);
sl@0
  1060
		--iLockedQCount;
sl@0
  1061
		}
sl@0
  1062
	else if (aPage->iType == TDynamicDirCachePage::EUnlocked)
sl@0
  1063
		{
sl@0
  1064
		aPage->Deque();
sl@0
  1065
		aPage->SetPageType(TDynamicDirCachePage::EUnknown);
sl@0
  1066
		--iUnlockedQCount;
sl@0
  1067
		}
sl@0
  1068
	else
sl@0
  1069
		{
sl@0
  1070
		ASSERT(0);
sl@0
  1071
		return KErrArgument;
sl@0
  1072
		}
sl@0
  1073
	return KErrNone;
sl@0
  1074
	}
sl@0
  1075
sl@0
  1076
/**
sl@0
  1077
Insert a page to the first position of locked queue or unlocked queue.
sl@0
  1078
@param	aPage	the pointer of the page to be inserted.
sl@0
  1079
@param	aType	the type of the queue to be inserted.
sl@0
  1080
@return	TInt	KErrArgument if aPage is invalid, otherwise KErrNone.
sl@0
  1081
*/
sl@0
  1082
TInt CDynamicDirCache::AddFirstOntoQueue(TDynamicDirCachePage* aPage, TDynamicDirCachePage::TPageType aType)
sl@0
  1083
	{
sl@0
  1084
	ASSERT(aPage);
sl@0
  1085
	if (!aPage)
sl@0
  1086
		return KErrArgument;
sl@0
  1087
sl@0
  1088
	if (aType == TDynamicDirCachePage::ELocked)
sl@0
  1089
		{
sl@0
  1090
		iLockedQ.AddFirst(*aPage);
sl@0
  1091
		aPage->SetPageType(TDynamicDirCachePage::ELocked);
sl@0
  1092
		++iLockedQCount;
sl@0
  1093
		}
sl@0
  1094
	else if (aType == TDynamicDirCachePage::EUnlocked)
sl@0
  1095
		{
sl@0
  1096
		iUnlockedQ.AddFirst(*aPage);
sl@0
  1097
		aPage->SetPageType(TDynamicDirCachePage::EUnlocked);
sl@0
  1098
		++iUnlockedQCount;
sl@0
  1099
		}
sl@0
  1100
	else
sl@0
  1101
		{
sl@0
  1102
		ASSERT(0);
sl@0
  1103
		return KErrArgument;
sl@0
  1104
		}
sl@0
  1105
sl@0
  1106
	return KErrNone;
sl@0
  1107
	}
sl@0
  1108
sl@0
  1109
/**
sl@0
  1110
Remove a page from the lookup table, indexed by the starting media address of the page content.
sl@0
  1111
@param	aPagePos	the starting media position of the page to be removed.
sl@0
  1112
*/
sl@0
  1113
TInt CDynamicDirCache::LookupTblRemove(TInt64 aPagePos)
sl@0
  1114
	{
sl@0
  1115
	if (aPagePos == 0)
sl@0
  1116
		{
sl@0
  1117
		return KErrNone;
sl@0
  1118
		}
sl@0
  1119
sl@0
  1120
	TInt r = iLookupTable.Remove(TLookupEntry(aPagePos, 0, NULL));
sl@0
  1121
	return r;
sl@0
  1122
	}
sl@0
  1123
sl@0
  1124
/**
sl@0
  1125
Insert a page to the lookup table, indexed by the starting media address of the page content.
sl@0
  1126
@param	aPagePos	the starting media position of the page to be inserted.
sl@0
  1127
*/
sl@0
  1128
TInt CDynamicDirCache::LookupTblAdd(TDynamicDirCachePage* aPage)
sl@0
  1129
	{
sl@0
  1130
	ASSERT(aPage);
sl@0
  1131
	if (!aPage)
sl@0
  1132
		return KErrArgument;
sl@0
  1133
sl@0
  1134
	if (aPage->StartPos() == 0)
sl@0
  1135
		{
sl@0
  1136
		return KErrNone;
sl@0
  1137
		}
sl@0
  1138
sl@0
  1139
	TInt r = iLookupTable.Insert(TLookupEntry(aPage->StartPos(), iPageSizeInBytes, aPage));
sl@0
  1140
	return r;
sl@0
  1141
	}
sl@0
  1142
sl@0
  1143
/**
sl@0
  1144
Reset the media address of the page to 0, also invalidate the page.
sl@0
  1145
@param	aPage	the pointer of the page to be reset.
sl@0
  1146
*/
sl@0
  1147
TInt CDynamicDirCache::ResetPagePos(TDynamicDirCachePage* aPage)
sl@0
  1148
	{
sl@0
  1149
	ASSERT(aPage);
sl@0
  1150
	if (!aPage)
sl@0
  1151
		return KErrArgument;
sl@0
  1152
sl@0
  1153
	aPage->ResetPos();
sl@0
  1154
	return KErrNone;
sl@0
  1155
	}
sl@0
  1156
sl@0
  1157
/**
sl@0
  1158
Search the lookup table to find the page start with a specific media address.
sl@0
  1159
@param	aPos	the starting media address to be searched.
sl@0
  1160
*/
sl@0
  1161
TDynamicDirCachePage* CDynamicDirCache::LookupTblFind(TInt64 aPos)
sl@0
  1162
	{
sl@0
  1163
	if (aPos == 0)
sl@0
  1164
		{
sl@0
  1165
		ASSERT(0);
sl@0
  1166
		return NULL;
sl@0
  1167
		}
sl@0
  1168
sl@0
  1169
	TLookupEntry* entry = iLookupTable.Find(TLookupEntry(aPos, 0, NULL));
sl@0
  1170
	if(entry)
sl@0
  1171
		{
sl@0
  1172
		// last entry on used queue is used as the 'active' page & may not be valid
sl@0
  1173
		if (!entry->iPage->IsValid())
sl@0
  1174
			return NULL;
sl@0
  1175
sl@0
  1176
		return entry->iPage;
sl@0
  1177
		}
sl@0
  1178
sl@0
  1179
	return NULL;
sl@0
  1180
	}