os/kernelhwsrv/userlibandfileserver/fileserver/sfat32/sl_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) 1996-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_cache.cpp
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
#include "sl_std.h"
sl@0
    19
#include "sl_cache.h"
sl@0
    20
sl@0
    21
//---------------------------------------------------------------------------------------------------------------------------------
sl@0
    22
sl@0
    23
/**
sl@0
    24
    CWTCachePage factory function.    
sl@0
    25
    @param  aPageSizeLog2 Log2(cache page size in bytes)
sl@0
    26
    @return a pointer to the created object.
sl@0
    27
*/
sl@0
    28
CWTCachePage* CWTCachePage::NewL(TUint32 aPageSizeLog2)
sl@0
    29
    {
sl@0
    30
    CWTCachePage* pSelf = new (ELeave)CWTCachePage;
sl@0
    31
    pSelf->ConstructL(aPageSizeLog2);
sl@0
    32
sl@0
    33
    return pSelf;
sl@0
    34
    }
sl@0
    35
sl@0
    36
/**
sl@0
    37
    2nd stage constructor.
sl@0
    38
    @param  aPageSizeLog2 Log2(cache page size in bytes)
sl@0
    39
*/
sl@0
    40
void CWTCachePage::ConstructL(TUint32 aPageSizeLog2)
sl@0
    41
    {
sl@0
    42
    iData.CreateMaxL(1 << aPageSizeLog2);
sl@0
    43
    }
sl@0
    44
sl@0
    45
CWTCachePage::CWTCachePage()
sl@0
    46
    {
sl@0
    47
    iStartPos = 0xDeadDeadul;
sl@0
    48
    iValid  = 0;
sl@0
    49
    }
sl@0
    50
sl@0
    51
CWTCachePage::~CWTCachePage() 
sl@0
    52
    { 
sl@0
    53
    iData.Close(); 
sl@0
    54
    }
sl@0
    55
sl@0
    56
sl@0
    57
sl@0
    58
//---------------------------------------------------------------------------------------------------------------------------------
sl@0
    59
sl@0
    60
CMediaWTCache::CMediaWTCache(TDriveInterface& aDrive)
sl@0
    61
          :iDrive(aDrive), iPageSizeLog2(0), iAllPagesValid(EFalse)
sl@0
    62
    {
sl@0
    63
    iCacheDisabled = EFalse;
sl@0
    64
    iCacheBasePos  = 0; 
sl@0
    65
    }
sl@0
    66
sl@0
    67
CMediaWTCache::~CMediaWTCache()
sl@0
    68
    {
sl@0
    69
    //-- delete pages
sl@0
    70
    TInt cnt = iPages.Count();
sl@0
    71
    while(cnt--)
sl@0
    72
        {
sl@0
    73
        delete iPages[cnt];
sl@0
    74
        }
sl@0
    75
sl@0
    76
    iPages.Close();
sl@0
    77
    }
sl@0
    78
sl@0
    79
sl@0
    80
/**
sl@0
    81
    Directory cache factory function.
sl@0
    82
sl@0
    83
    @param  aDrive  reference to the driver for media access.
sl@0
    84
    @param  aNumPages     number of cache pages to be created
sl@0
    85
    @param  aPageSizeLog2 Log2 of the page size in bytes
sl@0
    86
    
sl@0
    87
    @return a pointer to the created object.
sl@0
    88
*/
sl@0
    89
CMediaWTCache* CMediaWTCache::NewL(TDriveInterface& aDrive, TUint32 aNumPages, TUint32 aPageSizeLog2)
sl@0
    90
    {
sl@0
    91
#ifndef ENABLE_DEDICATED_DIR_CACHE    
sl@0
    92
    //-- dedicated directory cache isn't enabled
sl@0
    93
    (void)aDrive; //-- supress compiler's warning
sl@0
    94
    (void)aClusterSizeLog2;
sl@0
    95
    return NULL;
sl@0
    96
#else    
sl@0
    97
sl@0
    98
    //-- dedicated directory cache is enabled, create it
sl@0
    99
    ASSERT(aPageSizeLog2);
sl@0
   100
    ASSERT(aNumPages);
sl@0
   101
sl@0
   102
    CMediaWTCache* pSelf = new (ELeave) CMediaWTCache(aDrive);
sl@0
   103
    
sl@0
   104
    CleanupStack::PushL(pSelf);
sl@0
   105
    pSelf->ConstructL(aNumPages, aPageSizeLog2);
sl@0
   106
    CleanupStack::Pop();
sl@0
   107
sl@0
   108
    return pSelf;
sl@0
   109
sl@0
   110
#endif
sl@0
   111
    }
sl@0
   112
sl@0
   113
/**
sl@0
   114
    2nd stage constructor.
sl@0
   115
    @param  aNumPages number of pages in the directory cache.
sl@0
   116
    @param  aPageSizeLog2 Log2(single cache page size in bytes)
sl@0
   117
*/
sl@0
   118
void CMediaWTCache::ConstructL(TUint32 aNumPages, TUint32 aPageSizeLog2)
sl@0
   119
    {
sl@0
   120
    ASSERT(aNumPages && aPageSizeLog2);
sl@0
   121
    
sl@0
   122
    __PRINT2(_L("#CMediaWTCache::CreateL() Pages=%d, PageSize=%d"), aNumPages, 1<<aPageSizeLog2);
sl@0
   123
    
sl@0
   124
    iPageSizeLog2 = aPageSizeLog2; 
sl@0
   125
sl@0
   126
    //-- create cache pages
sl@0
   127
    for(TUint cnt=0; cnt<aNumPages; ++cnt)
sl@0
   128
        {
sl@0
   129
        CWTCachePage* pPage = CWTCachePage::NewL(aPageSizeLog2);
sl@0
   130
        iPages.Append(pPage);
sl@0
   131
        }
sl@0
   132
sl@0
   133
    InvalidateCache();  
sl@0
   134
    }
sl@0
   135
sl@0
   136
sl@0
   137
/**
sl@0
   138
    @return size of the cache in bytes. Can be 0.
sl@0
   139
*/
sl@0
   140
TUint32 CMediaWTCache::CacheSizeInBytes() const
sl@0
   141
    {
sl@0
   142
    const TUint32 cacheSz = iPages.Count() << iPageSizeLog2; //-- Page size is always power of 2
sl@0
   143
    return cacheSz;
sl@0
   144
    }
sl@0
   145
sl@0
   146
/**
sl@0
   147
Implementation of pure virtual function.
sl@0
   148
@see MWTCacheInterface::MakePageMRU()
sl@0
   149
*/
sl@0
   150
void CMediaWTCache::MakePageMRU(TInt64 /*aPos*/)
sl@0
   151
	{
sl@0
   152
	return;
sl@0
   153
	}
sl@0
   154
sl@0
   155
/**
sl@0
   156
Implementation of pure virtual function.
sl@0
   157
@see MWTCacheInterface::PageSizeInBytesLog2()
sl@0
   158
*/
sl@0
   159
TUint32 CMediaWTCache::PageSizeInBytesLog2() const
sl@0
   160
	{
sl@0
   161
	return iPageSizeLog2;
sl@0
   162
	}
sl@0
   163
sl@0
   164
/**
sl@0
   165
    Control method.
sl@0
   166
sl@0
   167
    @param  aFunction   control function
sl@0
   168
    @param  aParam1     just arbitrary parameter 
sl@0
   169
    @param  aParam2     just arbitrary parameter 
sl@0
   170
    @return Standard error code.
sl@0
   171
*/
sl@0
   172
sl@0
   173
TInt CMediaWTCache::Control(TUint32 aFunction, TUint32 aParam1, TAny* /*aParam2*/)
sl@0
   174
    {
sl@0
   175
    TInt nRes = KErrNotSupported;
sl@0
   176
sl@0
   177
#ifdef _DEBUG
sl@0
   178
    switch(aFunction)
sl@0
   179
        {
sl@0
   180
        //-- disable / enable cache, for debug
sl@0
   181
        //-- if aParam1 !=0 cache will be disabled, enabled otherwise
sl@0
   182
        case EDisableCache: 
sl@0
   183
            iCacheDisabled = aParam1 ? 1 : 0;
sl@0
   184
            nRes = KErrNone;
sl@0
   185
        break;
sl@0
   186
sl@0
   187
        case EDumpCache:
sl@0
   188
        break;
sl@0
   189
           
sl@0
   190
        case ECacheInfo:
sl@0
   191
        break;
sl@0
   192
   
sl@0
   193
        default:
sl@0
   194
            __PRINT1(_L("CMediaWTCache::Control() invalid function: %d"), aFunction);
sl@0
   195
            ASSERT(0);
sl@0
   196
        break;
sl@0
   197
        }
sl@0
   198
#else
sl@0
   199
    (void)aFunction; //-- supress warnings
sl@0
   200
    (void)aParam1;
sl@0
   201
    User::Invariant(); //-- don't call this method in release build
sl@0
   202
#endif //_DEBUG   
sl@0
   203
    
sl@0
   204
    return nRes;
sl@0
   205
    }
sl@0
   206
sl@0
   207
//-------------------------------------------------------------------------------------
sl@0
   208
/**
sl@0
   209
    Invalidate whole cache
sl@0
   210
*/
sl@0
   211
void CMediaWTCache::InvalidateCache(void)
sl@0
   212
    {
sl@0
   213
    const TUint nPages = iPages.Count();    
sl@0
   214
    for(TUint i=0; i<nPages; ++i)
sl@0
   215
        {
sl@0
   216
        iPages[i]->iValid=EFalse;
sl@0
   217
        }
sl@0
   218
sl@0
   219
    iAllPagesValid = EFalse;
sl@0
   220
    }
sl@0
   221
sl@0
   222
//-------------------------------------------------------------------------------------
sl@0
   223
/** 
sl@0
   224
    invalidate a single cache page if the aPos is cached (belongs to some page)
sl@0
   225
    If the cache user wants to invalidate some media address range, it will have to calculate 
sl@0
   226
    pages positions itself. The best way to do this - is to write another method that takes lenght of the 
sl@0
   227
    region being invalidated. 
sl@0
   228
sl@0
   229
    @param aPos media position. If it is cached, the corresponding single cache page will be marked as invalid
sl@0
   230
*/
sl@0
   231
void CMediaWTCache::InvalidateCachePage(TUint64 aPos)
sl@0
   232
    {
sl@0
   233
    const TUint nPages = iPages.Count();    
sl@0
   234
    for(TUint i=0; i<nPages; ++i)
sl@0
   235
        {
sl@0
   236
        if( iPages[i]->PosCached(aPos))  
sl@0
   237
            {
sl@0
   238
            iPages[i]->iValid=EFalse;
sl@0
   239
            iAllPagesValid = EFalse;
sl@0
   240
            break;
sl@0
   241
            }
sl@0
   242
        }
sl@0
   243
sl@0
   244
    }
sl@0
   245
sl@0
   246
//-------------------------------------------------------------------------------------
sl@0
   247
sl@0
   248
/**
sl@0
   249
    Find cache page by given media position.
sl@0
   250
    
sl@0
   251
    @param  aPos    linear media position
sl@0
   252
    @return positive cache page number or -1 if no pages containing data at aPos found.
sl@0
   253
*/
sl@0
   254
TInt CMediaWTCache::FindPageByPos(TInt64 aPos) const
sl@0
   255
    {
sl@0
   256
    const TUint nPages = iPages.Count();    
sl@0
   257
    for(TUint i=0; i<nPages; ++i)
sl@0
   258
        {
sl@0
   259
        if( iPages[i]->PosCached(aPos))  
sl@0
   260
            return i; 
sl@0
   261
        }
sl@0
   262
sl@0
   263
    return KErrNotFound;
sl@0
   264
    }
sl@0
   265
sl@0
   266
/**
sl@0
   267
    Push given page aPageNo to the 1st position in the pages array. Used for LRU mechanism
sl@0
   268
    
sl@0
   269
    @param  aPageNo page number to be made LRU
sl@0
   270
*/
sl@0
   271
void CMediaWTCache::MakePageLRU(TInt aPageNo)
sl@0
   272
    {
sl@0
   273
    ASSERT(aPageNo >=0);
sl@0
   274
sl@0
   275
    if(aPageNo <= 0)
sl@0
   276
        return; //-- nothing to do
sl@0
   277
    
sl@0
   278
    const TInt nPages = iPages.Count();
sl@0
   279
    ASSERT(aPageNo < nPages);
sl@0
   280
sl@0
   281
    if(aPageNo < nPages)
sl@0
   282
        {
sl@0
   283
        CWTCachePage* pPage=iPages[aPageNo];
sl@0
   284
    
sl@0
   285
        iPages.Remove(aPageNo);
sl@0
   286
        iPages.Insert(pPage,0); //-- insert the pointer to the 1st position in the array
sl@0
   287
        ASSERT(nPages == iPages.Count());
sl@0
   288
        }
sl@0
   289
    }
sl@0
   290
sl@0
   291
/*
sl@0
   292
    Find a spare page or evict the last from LRU list
sl@0
   293
    
sl@0
   294
    @return page number
sl@0
   295
*/
sl@0
   296
TUint32  CMediaWTCache::GrabPage() const
sl@0
   297
    {
sl@0
   298
    const TUint nPages = iPages.Count();
sl@0
   299
sl@0
   300
    if(!iAllPagesValid)
sl@0
   301
        {//-- try to find unused cache page
sl@0
   302
        for(TUint i=0; i<nPages; ++i)
sl@0
   303
            {
sl@0
   304
            if(! iPages[i]->iValid)
sl@0
   305
                return i; //-- found unused page
sl@0
   306
            }
sl@0
   307
        }
sl@0
   308
sl@0
   309
    //-- no spare pages, evict the last one, it shall be last used
sl@0
   310
    iAllPagesValid = ETrue;
sl@0
   311
    return nPages-1;
sl@0
   312
    }
sl@0
   313
sl@0
   314
/*
sl@0
   315
    Find a spare page or evict the last from LRU list, then read data to this page from media starting from aPos
sl@0
   316
    
sl@0
   317
    @param  aPos    media linear position from where the data will be read to the page
sl@0
   318
    @return cache page number
sl@0
   319
*/
sl@0
   320
TUint32 CMediaWTCache::GrabReadPageL(TInt64 aPos)
sl@0
   321
    {
sl@0
   322
    //-- find a spare or page to evict
sl@0
   323
    TUint nPage = GrabPage();
sl@0
   324
    CWTCachePage& page = *iPages[nPage]; 
sl@0
   325
sl@0
   326
    //-- read data to this page
sl@0
   327
    page.iStartPos = CalcPageStartPos(aPos);
sl@0
   328
    
sl@0
   329
    __PRINT4(_L("#CMediaWTCache::GrabReadPageL() Reading page:%d, Pos=0x%x, PageStartPos=0x%x, page=0x%X"),nPage, (TUint32)aPos, (TUint32)page.iStartPos, iPages[nPage]);
sl@0
   330
        
sl@0
   331
    const TInt nErr = iDrive.ReadNonCritical(page.iStartPos, PageSize(), page.iData);
sl@0
   332
    if(nErr !=KErrNone)
sl@0
   333
        {//-- some serious problem occured during reading, invalidate cache.
sl@0
   334
        InvalidateCache();
sl@0
   335
        User::Leave(nErr);
sl@0
   336
        }
sl@0
   337
    
sl@0
   338
    page.iValid = ETrue;
sl@0
   339
sl@0
   340
    return nPage;
sl@0
   341
    }
sl@0
   342
sl@0
   343
/**
sl@0
   344
    Try to find the page with cached data at "aPos" media position.
sl@0
   345
    If such page found, returns its number, otherwise takes least recently used page and reads data there.
sl@0
   346
    
sl@0
   347
    @param  aPos    media linear position to find in the cache
sl@0
   348
    @return cache page number
sl@0
   349
sl@0
   350
*/
sl@0
   351
TUint32 CMediaWTCache::FindOrGrabReadPageL(TInt64 aPos)
sl@0
   352
    {
sl@0
   353
    //-- find out if aPos is in cache
sl@0
   354
    TInt nPage=FindPageByPos(aPos);
sl@0
   355
    
sl@0
   356
    if(nPage < 0)
sl@0
   357
        {//-- no page contains data to read
sl@0
   358
        nPage = GrabReadPageL(aPos); //-- find a spare page and read data into it
sl@0
   359
        }
sl@0
   360
sl@0
   361
    return nPage;
sl@0
   362
    }
sl@0
   363
sl@0
   364
/**
sl@0
   365
    Finds out if the media position "aPosToSearch" is in the cache and returns cache page information in this case.
sl@0
   366
sl@0
   367
    @param  aPosToSearch    linear media position to lookup in the cache
sl@0
   368
    @param  aCachedPosStart if "aPosToSearch" is cached, here will be media position of this page start
sl@0
   369
    
sl@0
   370
    @return 0 if aPosToSearch isn't cached, otherwise  cache page size in bytes (see also aCachedPosStart).
sl@0
   371
*/
sl@0
   372
TUint32 CMediaWTCache::PosCached(const TInt64& aPosToSearch, TInt64& aCachedPosStart)
sl@0
   373
    {
sl@0
   374
    TInt nPage = FindPageByPos(aPosToSearch);
sl@0
   375
    if(nPage <0 )
sl@0
   376
        return 0; //-- cache page containing aPos not found
sl@0
   377
sl@0
   378
    aCachedPosStart = iPages[nPage]->iStartPos;
sl@0
   379
    
sl@0
   380
    return PageSize();
sl@0
   381
    }
sl@0
   382
sl@0
   383
/**
sl@0
   384
    Read data from the media through the directory cache.
sl@0
   385
    
sl@0
   386
    @param  aPos    linear media position to start reading with
sl@0
   387
    @param  aLength how many bytes to read
sl@0
   388
    @param  aDes    data will be placed there
sl@0
   389
*/
sl@0
   390
void CMediaWTCache::ReadL(TInt64 aPos,TInt aLength,TDes8& aDes)
sl@0
   391
    {
sl@0
   392
    
sl@0
   393
#ifdef _DEBUG
sl@0
   394
    if(iCacheDisabled)
sl@0
   395
        {//-- cache is disabled for debug purposes
sl@0
   396
        User::LeaveIfError(iDrive.ReadNonCritical(aPos, aLength, aDes));
sl@0
   397
        return;
sl@0
   398
        }
sl@0
   399
#endif //_DEBUG
sl@0
   400
sl@0
   401
    const TUint32 PageSz = PageSize();//-- cache page size
sl@0
   402
sl@0
   403
    //-- find out if aPos is in cache. If not, find a spare page and read data there
sl@0
   404
    TInt nPage = FindOrGrabReadPageL(aPos);
sl@0
   405
    CWTCachePage* pPage = iPages[nPage];
sl@0
   406
sl@0
   407
    const TUint32 bytesToPageEnd = (TUint32)(pPage->iStartPos+PageSz - aPos); //-- number of bytes from aPos to the end of the page
sl@0
   408
sl@0
   409
//    __PRINT5(_L("CMediaWTCache::ReadL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, aLength, pPage->iStartPos, PageSz, bytesToPageEnd);
sl@0
   410
    if((TUint32)aLength <= bytesToPageEnd) 
sl@0
   411
        {//-- the data section is in the cache page entirely, take data directly from the cache
sl@0
   412
        aDes.Copy(pPage->PtrInCachePage(aPos), aLength);
sl@0
   413
        }
sl@0
   414
    else
sl@0
   415
        {//-- Data to be read cross cache page boundary or probably we have more than 1 page to read
sl@0
   416
sl@0
   417
        TUint32 dataLen(aLength);   //-- current data length
sl@0
   418
        TInt64  currMediaPos(aPos); //-- current media position
sl@0
   419
sl@0
   420
        //-- 1. read data that are already in the current page
sl@0
   421
        aDes.Copy(pPage->PtrInCachePage(currMediaPos), bytesToPageEnd);
sl@0
   422
sl@0
   423
        dataLen -= bytesToPageEnd;
sl@0
   424
        currMediaPos += bytesToPageEnd;
sl@0
   425
sl@0
   426
        //-- 2. read whole pages of data
sl@0
   427
        while(dataLen >= PageSz)
sl@0
   428
            {
sl@0
   429
            nPage = FindOrGrabReadPageL(currMediaPos); //-- find out if currMediaPos is in cache. If not, find a spare page and read data there
sl@0
   430
            pPage = iPages[nPage];
sl@0
   431
sl@0
   432
            aDes.Append(pPage->PtrInCachePage(currMediaPos),PageSz);
sl@0
   433
        
sl@0
   434
            dataLen -= PageSz;
sl@0
   435
            currMediaPos += PageSz;
sl@0
   436
        
sl@0
   437
            MakePageLRU(nPage); //-- push the page to the top of the priority list
sl@0
   438
            }
sl@0
   439
sl@0
   440
        //-- 3. read the rest of the data
sl@0
   441
        if(dataLen >0)
sl@0
   442
            {
sl@0
   443
            nPage = FindOrGrabReadPageL(currMediaPos); //-- find out if currMediaPos is in cache. If not, find a spare page and read data there
sl@0
   444
            pPage = iPages[nPage];
sl@0
   445
sl@0
   446
            aDes.Append(pPage->PtrInCachePage(currMediaPos), dataLen);
sl@0
   447
            }
sl@0
   448
sl@0
   449
        } //else((TUint32)aLength <= bytesToPageEnd) 
sl@0
   450
sl@0
   451
sl@0
   452
    MakePageLRU(nPage); //-- push the page to the top of the priority list
sl@0
   453
    
sl@0
   454
    }
sl@0
   455
sl@0
   456
/**
sl@0
   457
    Write data to the media through the directory cache.
sl@0
   458
    
sl@0
   459
    @param  aPos    linear media position to start writing with
sl@0
   460
    @param  aDes    data to write
sl@0
   461
*/
sl@0
   462
void CMediaWTCache::WriteL(TInt64 aPos,const TDesC8& aDes)
sl@0
   463
    {
sl@0
   464
sl@0
   465
#ifdef _DEBUG
sl@0
   466
    if(iCacheDisabled)
sl@0
   467
        {//-- cache is disabled for debug purposes
sl@0
   468
        User::LeaveIfError(iDrive.WriteCritical(aPos,aDes));
sl@0
   469
        return;
sl@0
   470
        }
sl@0
   471
#endif //_DEBUG
sl@0
   472
sl@0
   473
          TUint32 dataLen = aDes.Size();
sl@0
   474
    const TUint8* pData   = aDes.Ptr();
sl@0
   475
    const TUint32 PageSz  = PageSize(); //-- cache page size
sl@0
   476
sl@0
   477
    //-- find out if aPos is in cache. If not, find a spare page and read data there
sl@0
   478
    TInt nPage = FindOrGrabReadPageL(aPos);
sl@0
   479
    CWTCachePage* pPage = iPages[nPage];
sl@0
   480
sl@0
   481
    const TUint32 bytesToPageEnd = (TUint32)(pPage->iStartPos+PageSize() - aPos); //-- number of bytes from aPos to the end of the page
sl@0
   482
//    __PRINT5(_L("CMediaWTCache::WriteL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, dataLen, pPage->iStartPos, PageSz, bytesToPageEnd);
sl@0
   483
    if(dataLen <= bytesToPageEnd)
sl@0
   484
        {//-- data section completely fits to the cache page
sl@0
   485
        Mem::Copy(pPage->PtrInCachePage(aPos), pData, dataLen);   //-- update cache
sl@0
   486
        }
sl@0
   487
    else
sl@0
   488
        {//-- Data to be written cross cache page boundary or probably we have more than 1 page to write
sl@0
   489
sl@0
   490
        TInt64  currMediaPos(aPos); //-- current media position
sl@0
   491
sl@0
   492
        //-- 1. update the current page
sl@0
   493
        Mem::Copy(pPage->PtrInCachePage(currMediaPos), pData, bytesToPageEnd);
sl@0
   494
sl@0
   495
        pData += bytesToPageEnd;
sl@0
   496
        currMediaPos += bytesToPageEnd;
sl@0
   497
        dataLen -= bytesToPageEnd;
sl@0
   498
sl@0
   499
        //-- 2. write whole pages of data to the cache
sl@0
   500
        while(dataLen >= PageSz)
sl@0
   501
            {
sl@0
   502
            nPage = FindPageByPos(currMediaPos); //-- ?? shall we read data there ??
sl@0
   503
            if(nPage >=0)
sl@0
   504
                {
sl@0
   505
                pPage = iPages[nPage];
sl@0
   506
                Mem::Copy(pPage->PtrInCachePage(currMediaPos), pData, PageSz);
sl@0
   507
                MakePageLRU(nPage); //-- push the page to the top of the priority list
sl@0
   508
                }
sl@0
   509
            else
sl@0
   510
                nPage=0;
sl@0
   511
sl@0
   512
            pData += PageSz;
sl@0
   513
            currMediaPos += PageSz;
sl@0
   514
            dataLen -= PageSz;
sl@0
   515
            }
sl@0
   516
sl@0
   517
        //-- 3. write the rest of the data
sl@0
   518
        if(dataLen)
sl@0
   519
            {
sl@0
   520
            nPage = FindOrGrabReadPageL(currMediaPos); //-- find out if currMediaPos is in cache. If not, find a spare page and read data there
sl@0
   521
            pPage = iPages[nPage];
sl@0
   522
sl@0
   523
            Mem::Copy(pPage->PtrInCachePage(currMediaPos), pData, dataLen);
sl@0
   524
            }
sl@0
   525
sl@0
   526
        }// else(dataLen <= bytesToPageEnd)
sl@0
   527
sl@0
   528
    
sl@0
   529
    //-- write data to the media
sl@0
   530
    const TInt nErr = iDrive.WriteCritical(aPos,aDes); 
sl@0
   531
    if(nErr != KErrNone)
sl@0
   532
        {//-- some serious problem occured during writing, invalidate cache.
sl@0
   533
        InvalidateCache();
sl@0
   534
        User::Leave(nErr);
sl@0
   535
        }
sl@0
   536
sl@0
   537
    MakePageLRU(nPage); //-- push the page to the top of the priority list
sl@0
   538
    }
sl@0
   539
sl@0
   540
sl@0
   541
sl@0
   542
sl@0
   543
sl@0
   544
sl@0
   545
sl@0
   546
sl@0
   547
sl@0
   548
sl@0
   549
sl@0
   550
sl@0
   551
sl@0
   552
sl@0
   553
sl@0
   554
sl@0
   555