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