--- /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<<aPageSizeLog2);
+
+ iPageSizeLog2 = aPageSizeLog2;
+
+ //-- create cache pages
+ for(TUint cnt=0; cnt<aNumPages; ++cnt)
+ {
+ CWTCachePage* pPage = CWTCachePage::NewL(aPageSizeLog2);
+ iPages.Append(pPage);
+ }
+
+ InvalidateCache();
+ }
+
+
+/**
+ @return size of the cache in bytes. Can be 0.
+*/
+TUint32 CMediaWTCache::CacheSizeInBytes() const
+ {
+ const TUint32 cacheSz = iPages.Count() << iPageSizeLog2; //-- Page size is always power of 2
+ return cacheSz;
+ }
+
+/**
+Implementation of pure virtual function.
+@see MWTCacheInterface::MakePageMRU()
+*/
+void CMediaWTCache::MakePageMRU(TInt64 /*aPos*/)
+ {
+ return;
+ }
+
+/**
+Implementation of pure virtual function.
+@see MWTCacheInterface::PageSizeInBytesLog2()
+*/
+TUint32 CMediaWTCache::PageSizeInBytesLog2() const
+ {
+ return iPageSizeLog2;
+ }
+
+/**
+ Control method.
+
+ @param aFunction control function
+ @param aParam1 just arbitrary parameter
+ @param aParam2 just arbitrary parameter
+ @return Standard error code.
+*/
+
+TInt CMediaWTCache::Control(TUint32 aFunction, TUint32 aParam1, TAny* /*aParam2*/)
+ {
+ TInt nRes = KErrNotSupported;
+
+#ifdef _DEBUG
+ switch(aFunction)
+ {
+ //-- disable / enable cache, for debug
+ //-- if aParam1 !=0 cache will be disabled, enabled otherwise
+ case EDisableCache:
+ iCacheDisabled = aParam1 ? 1 : 0;
+ nRes = KErrNone;
+ break;
+
+ case EDumpCache:
+ break;
+
+ case ECacheInfo:
+ break;
+
+ default:
+ __PRINT1(_L("CMediaWTCache::Control() invalid function: %d"), aFunction);
+ ASSERT(0);
+ break;
+ }
+#else
+ (void)aFunction; //-- supress warnings
+ (void)aParam1;
+ User::Invariant(); //-- don't call this method in release build
+#endif //_DEBUG
+
+ return nRes;
+ }
+
+//-------------------------------------------------------------------------------------
+/**
+ Invalidate whole cache
+*/
+void CMediaWTCache::InvalidateCache(void)
+ {
+ const TUint nPages = iPages.Count();
+ for(TUint i=0; i<nPages; ++i)
+ {
+ iPages[i]->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; i<nPages; ++i)
+ {
+ if( iPages[i]->PosCached(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; i<nPages; ++i)
+ {
+ if( iPages[i]->PosCached(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; i<nPages; ++i)
+ {
+ if(! iPages[i]->iValid)
+ 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
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+