diff -r a41df078684a -r 4122176ea935 userlibandfileserver/fileserver/sfat32/sl_cache.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/sfat32/sl_cache.cpp Mon Dec 21 16:14:42 2009 +0000 @@ -0,0 +1,555 @@ +// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// f32\sfat\sl_cache.cpp +// +// + +#include "sl_std.h" +#include "sl_cache.h" + +//--------------------------------------------------------------------------------------------------------------------------------- + +/** + CWTCachePage factory function. + @param aPageSizeLog2 Log2(cache page size in bytes) + @return a pointer to the created object. +*/ +CWTCachePage* CWTCachePage::NewL(TUint32 aPageSizeLog2) + { + CWTCachePage* pSelf = new (ELeave)CWTCachePage; + pSelf->ConstructL(aPageSizeLog2); + + return pSelf; + } + +/** + 2nd stage constructor. + @param aPageSizeLog2 Log2(cache page size in bytes) +*/ +void CWTCachePage::ConstructL(TUint32 aPageSizeLog2) + { + iData.CreateMaxL(1 << aPageSizeLog2); + } + +CWTCachePage::CWTCachePage() + { + iStartPos = 0xDeadDeadul; + iValid = 0; + } + +CWTCachePage::~CWTCachePage() + { + iData.Close(); + } + + + +//--------------------------------------------------------------------------------------------------------------------------------- + +CMediaWTCache::CMediaWTCache(TFatDriveInterface& aDrive) + :iDrive(aDrive), iPageSizeLog2(0), iAllPagesValid(EFalse) + { + iCacheDisabled = EFalse; + iCacheBasePos = 0; + } + +CMediaWTCache::~CMediaWTCache() + { + //-- delete pages + TInt cnt = iPages.Count(); + while(cnt--) + { + delete iPages[cnt]; + } + + iPages.Close(); + } + + +/** + Directory cache factory function. + + @param aDrive reference to the driver for media access. + @param aNumPages number of cache pages to be created + @param aPageSizeLog2 Log2 of the page size in bytes + + @return a pointer to the created object. +*/ +CMediaWTCache* CMediaWTCache::NewL(TFatDriveInterface& aDrive, TUint32 aNumPages, TUint32 aPageSizeLog2) + { +#ifndef ENABLE_DEDICATED_DIR_CACHE + //-- dedicated directory cache isn't enabled + (void)aDrive; //-- supress compiler's warning + (void)aClusterSizeLog2; + return NULL; +#else + + //-- dedicated directory cache is enabled, create it + ASSERT(aPageSizeLog2); + ASSERT(aNumPages); + + CMediaWTCache* pSelf = new (ELeave) CMediaWTCache(aDrive); + + CleanupStack::PushL(pSelf); + pSelf->ConstructL(aNumPages, aPageSizeLog2); + CleanupStack::Pop(); + + return pSelf; + +#endif + } + +/** + 2nd stage constructor. + @param aNumPages number of pages in the directory cache. + @param aPageSizeLog2 Log2(single cache page size in bytes) +*/ +void CMediaWTCache::ConstructL(TUint32 aNumPages, TUint32 aPageSizeLog2) + { + ASSERT(aNumPages && aPageSizeLog2); + + __PRINT2(_L("#CMediaWTCache::CreateL() Pages=%d, PageSize=%d"), aNumPages, 1<iValid=EFalse; + } + + iAllPagesValid = EFalse; + } + +//------------------------------------------------------------------------------------- +/** + invalidate a single cache page if the aPos is cached (belongs to some page) + If the cache user wants to invalidate some media address range, it will have to calculate + pages positions itself. The best way to do this - is to write another method that takes lenght of the + region being invalidated. + + @param aPos media position. If it is cached, the corresponding single cache page will be marked as invalid +*/ +void CMediaWTCache::InvalidateCachePage(TUint64 aPos) + { + const TUint nPages = iPages.Count(); + for(TUint i=0; iPosCached(aPos)) + { + iPages[i]->iValid=EFalse; + iAllPagesValid = EFalse; + break; + } + } + + } + +//------------------------------------------------------------------------------------- + +/** + Find cache page by given media position. + + @param aPos linear media position + @return positive cache page number or -1 if no pages containing data at aPos found. +*/ +TInt CMediaWTCache::FindPageByPos(TInt64 aPos) const + { + const TUint nPages = iPages.Count(); + for(TUint i=0; iPosCached(aPos)) + return i; + } + + return KErrNotFound; + } + +/** + Push given page aPageNo to the 1st position in the pages array. Used for LRU mechanism + + @param aPageNo page number to be made LRU +*/ +void CMediaWTCache::MakePageLRU(TInt aPageNo) + { + ASSERT(aPageNo >=0); + + if(aPageNo <= 0) + return; //-- nothing to do + + const TInt nPages = iPages.Count(); + ASSERT(aPageNo < nPages); + + if(aPageNo < nPages) + { + CWTCachePage* pPage=iPages[aPageNo]; + + iPages.Remove(aPageNo); + iPages.Insert(pPage,0); //-- insert the pointer to the 1st position in the array + ASSERT(nPages == iPages.Count()); + } + } + +/* + Find a spare page or evict the last from LRU list + + @return page number +*/ +TUint32 CMediaWTCache::GrabPage() const + { + const TUint nPages = iPages.Count(); + + if(!iAllPagesValid) + {//-- try to find unused cache page + for(TUint i=0; iiValid) + return i; //-- found unused page + } + } + + //-- no spare pages, evict the last one, it shall be last used + iAllPagesValid = ETrue; + return nPages-1; + } + +/* + Find a spare page or evict the last from LRU list, then read data to this page from media starting from aPos + + @param aPos media linear position from where the data will be read to the page + @return cache page number +*/ +TUint32 CMediaWTCache::GrabReadPageL(TInt64 aPos) + { + //-- find a spare or page to evict + TUint nPage = GrabPage(); + CWTCachePage& page = *iPages[nPage]; + + //-- read data to this page + page.iStartPos = CalcPageStartPos(aPos); + + __PRINT4(_L("#CMediaWTCache::GrabReadPageL() Reading page:%d, Pos=0x%x, PageStartPos=0x%x, page=0x%X"),nPage, (TUint32)aPos, (TUint32)page.iStartPos, iPages[nPage]); + + const TInt nErr = iDrive.ReadNonCritical(page.iStartPos, PageSize(), page.iData); + if(nErr !=KErrNone) + {//-- some serious problem occured during reading, invalidate cache. + InvalidateCache(); + User::Leave(nErr); + } + + page.iValid = ETrue; + + return nPage; + } + +/** + Try to find the page with cached data at "aPos" media position. + If such page found, returns its number, otherwise takes least recently used page and reads data there. + + @param aPos media linear position to find in the cache + @return cache page number + +*/ +TUint32 CMediaWTCache::FindOrGrabReadPageL(TInt64 aPos) + { + //-- find out if aPos is in cache + TInt nPage=FindPageByPos(aPos); + + if(nPage < 0) + {//-- no page contains data to read + nPage = GrabReadPageL(aPos); //-- find a spare page and read data into it + } + + return nPage; + } + +/** + Finds out if the media position "aPosToSearch" is in the cache and returns cache page information in this case. + + @param aPosToSearch linear media position to lookup in the cache + @param aCachedPosStart if "aPosToSearch" is cached, here will be media position of this page start + + @return 0 if aPosToSearch isn't cached, otherwise cache page size in bytes (see also aCachedPosStart). +*/ +TUint32 CMediaWTCache::PosCached(const TInt64& aPosToSearch, TInt64& aCachedPosStart) + { + TInt nPage = FindPageByPos(aPosToSearch); + if(nPage <0 ) + return 0; //-- cache page containing aPos not found + + aCachedPosStart = iPages[nPage]->iStartPos; + + return PageSize(); + } + +/** + Read data from the media through the directory cache. + + @param aPos linear media position to start reading with + @param aLength how many bytes to read + @param aDes data will be placed there +*/ +void CMediaWTCache::ReadL(TInt64 aPos,TInt aLength,TDes8& aDes) + { + +#ifdef _DEBUG + if(iCacheDisabled) + {//-- cache is disabled for debug purposes + User::LeaveIfError(iDrive.ReadNonCritical(aPos, aLength, aDes)); + return; + } +#endif //_DEBUG + + const TUint32 PageSz = PageSize();//-- cache page size + + //-- find out if aPos is in cache. If not, find a spare page and read data there + TInt nPage = FindOrGrabReadPageL(aPos); + CWTCachePage* pPage = iPages[nPage]; + + const TUint32 bytesToPageEnd = (TUint32)(pPage->iStartPos+PageSz - aPos); //-- number of bytes from aPos to the end of the page + +// __PRINT5(_L("CMediaWTCache::ReadL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, aLength, pPage->iStartPos, PageSz, bytesToPageEnd); + if((TUint32)aLength <= bytesToPageEnd) + {//-- the data section is in the cache page entirely, take data directly from the cache + aDes.Copy(pPage->PtrInCachePage(aPos), aLength); + } + else + {//-- Data to be read cross cache page boundary or probably we have more than 1 page to read + + TUint32 dataLen(aLength); //-- current data length + TInt64 currMediaPos(aPos); //-- current media position + + //-- 1. read data that are already in the current page + aDes.Copy(pPage->PtrInCachePage(currMediaPos), bytesToPageEnd); + + dataLen -= bytesToPageEnd; + currMediaPos += bytesToPageEnd; + + //-- 2. read whole pages of data + while(dataLen >= PageSz) + { + nPage = FindOrGrabReadPageL(currMediaPos); //-- find out if currMediaPos is in cache. If not, find a spare page and read data there + pPage = iPages[nPage]; + + aDes.Append(pPage->PtrInCachePage(currMediaPos),PageSz); + + dataLen -= PageSz; + currMediaPos += PageSz; + + MakePageLRU(nPage); //-- push the page to the top of the priority list + } + + //-- 3. read the rest of the data + if(dataLen >0) + { + nPage = FindOrGrabReadPageL(currMediaPos); //-- find out if currMediaPos is in cache. If not, find a spare page and read data there + pPage = iPages[nPage]; + + aDes.Append(pPage->PtrInCachePage(currMediaPos), dataLen); + } + + } //else((TUint32)aLength <= bytesToPageEnd) + + + MakePageLRU(nPage); //-- push the page to the top of the priority list + + } + +/** + Write data to the media through the directory cache. + + @param aPos linear media position to start writing with + @param aDes data to write +*/ +void CMediaWTCache::WriteL(TInt64 aPos,const TDesC8& aDes) + { + +#ifdef _DEBUG + if(iCacheDisabled) + {//-- cache is disabled for debug purposes + User::LeaveIfError(iDrive.WriteCritical(aPos,aDes)); + return; + } +#endif //_DEBUG + + TUint32 dataLen = aDes.Size(); + const TUint8* pData = aDes.Ptr(); + const TUint32 PageSz = PageSize(); //-- cache page size + + //-- find out if aPos is in cache. If not, find a spare page and read data there + TInt nPage = FindOrGrabReadPageL(aPos); + CWTCachePage* pPage = iPages[nPage]; + + const TUint32 bytesToPageEnd = (TUint32)(pPage->iStartPos+PageSize() - aPos); //-- number of bytes from aPos to the end of the page +// __PRINT5(_L("CMediaWTCache::WriteL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, dataLen, pPage->iStartPos, PageSz, bytesToPageEnd); + if(dataLen <= bytesToPageEnd) + {//-- data section completely fits to the cache page + Mem::Copy(pPage->PtrInCachePage(aPos), pData, dataLen); //-- update cache + } + else + {//-- Data to be written cross cache page boundary or probably we have more than 1 page to write + + TInt64 currMediaPos(aPos); //-- current media position + + //-- 1. update the current page + Mem::Copy(pPage->PtrInCachePage(currMediaPos), pData, bytesToPageEnd); + + pData += bytesToPageEnd; + currMediaPos += bytesToPageEnd; + dataLen -= bytesToPageEnd; + + //-- 2. write whole pages of data to the cache + while(dataLen >= PageSz) + { + nPage = FindPageByPos(currMediaPos); //-- ?? shall we read data there ?? + if(nPage >=0) + { + pPage = iPages[nPage]; + Mem::Copy(pPage->PtrInCachePage(currMediaPos), pData, PageSz); + MakePageLRU(nPage); //-- push the page to the top of the priority list + } + else + nPage=0; + + pData += PageSz; + currMediaPos += PageSz; + dataLen -= PageSz; + } + + //-- 3. write the rest of the data + if(dataLen) + { + nPage = FindOrGrabReadPageL(currMediaPos); //-- find out if currMediaPos is in cache. If not, find a spare page and read data there + pPage = iPages[nPage]; + + Mem::Copy(pPage->PtrInCachePage(currMediaPos), pData, dataLen); + } + + }// else(dataLen <= bytesToPageEnd) + + + //-- write data to the media + const TInt nErr = iDrive.WriteCritical(aPos,aDes); + if(nErr != KErrNone) + {//-- some serious problem occured during writing, invalidate cache. + InvalidateCache(); + User::Leave(nErr); + } + + MakePageLRU(nPage); //-- push the page to the top of the priority list + } + + + + + + + + + + + + + + + + +