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