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