diff -r 56f325a607ea -r 0173bcd7697c userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp --- a/userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp Wed Dec 23 11:43:31 2009 +0000 +++ b/userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp Thu Jan 07 13:38:45 2010 +0200 @@ -45,7 +45,7 @@ iValid(EFalse), iLocked(EFalse) { -// __PRINT3(_L("TDynamicDirCachePage::TDynamicDirCachePage(aStartMedPos=%lx, aStartRamAddr=0x%X, aPageSize=%u)"), aStartMedPos, aStartRamAddr, PageSizeInBytes()); + //__PRINT3(_L("TDynamicDirCachePage::TDynamicDirCachePage(aStartMedPos=%lx, aStartRamAddr=0x%X, aPageSize=%u)"), aStartMedPos, aStartRamAddr, PageSizeInBytes()); iType = EUnknown; } @@ -71,7 +71,7 @@ /////////////////////////////// class CDynamicDirCache /////////////////////////// CDynamicDirCache::~CDynamicDirCache() { -// __PRINT(_L("CDynamicDirCache::~CDynamicDirCache()")); + __PRINT(_L("CDynamicDirCache::~CDynamicDirCache()")); // we should never decommit locked pages while (!iLockedQ.IsEmpty()) @@ -93,8 +93,6 @@ } ASSERT(iUnlockedQCount == 0); - delete iActivePage; - ASSERT(iLookupTable.Count() == 0); iLookupTable.Close(); if (iCacheMemoryClient) @@ -108,7 +106,7 @@ @param aMaxPageNum the maximum page number for the cache, includes iActive page, locked pages and unlocked pages. @param aPageSizeInBytesLog2 the log2 value of page size in bytes, assumes page size is always a power of two */ -CDynamicDirCache::CDynamicDirCache(TFatDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeInBytesLog2) +CDynamicDirCache::CDynamicDirCache(TDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeInBytesLog2) :iPageSizeLog2(aPageSizeInBytesLog2), iMinSizeInPages(aMinPageNum), iMaxSizeInPages(aMaxPageNum), @@ -155,22 +153,30 @@ User::Leave(KErrNoMemory); } - // reserve active page - iActivePage = AllocateAndLockNewPageL(0); - ASSERT(iActivePage); - if (!iActivePage) + + // allocate as many permanently locked pages as there are threads - plus one + // otherwise DoMakePageMRU() won't work properly with only one thread + //-- At present moment the size of TDrive thread pool is 1 (1 drive thread in a pool) + iPermanentlyAllocatedPageCount = 1; + + if (iPermanentlyAllocatedPageCount > iMinSizeInPages) + iMinSizeInPages = iPermanentlyAllocatedPageCount; + + for (TUint n=0; nSetPageType(TDynamicDirCachePage::EActivePage); + } /** Static factory function of CDynamicDirCache */ -CDynamicDirCache* CDynamicDirCache::NewL(TFatDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeLog2, const TDesC& aClientName) +CDynamicDirCache* CDynamicDirCache::NewL(TDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeLog2, const TDesC& aClientName) { -// __PRINT3(_L("CDynamicDirCache::NewL(MinPageNum=%u, MaxPageNum=%u, page=%u)"), aMinPageNum, aMaxPageNum, 1<ConstructL(aClientName); @@ -215,12 +221,13 @@ } /** -Read data from a single page. If the page is not found or not valid anymore, read media onto iActive page -first. -@param aPos the starting position of the media address to be read. -@param aLength the length of the content to be read. -@param aDes the descriptor to contain the content. -@pre aLength should be no more than page size. + Read data from a single page. If the page is not found or not valid anymore, read media onto iActive page first. + The data will be _Appended_ the the descriptor aDes. The caller is responsible for maintaining this descriptor. + + @param aPos the starting position of the media address to be read. + @param aLength the length of the content to be read. + @param aDes the descriptor to contain the content. + @pre aLength should be no more than page size. */ void CDynamicDirCache::ReadDataFromSinglePageL(TInt64 aPos, TInt aLength, TDes8& aDes) { @@ -231,8 +238,9 @@ // lock page before reading, if (LockPage(pPage) != NULL) { - // read data - aDes.Copy(pPage->PtrInPage(aPos), aLength); + // read data and append them to the descriptor + aDes.Append(pPage->PtrInPage(aPos), aLength); + // if page is from unlocked queue, insert it onto the last page of the locked // queue. this is to avoid excessive locking and unlocking operations that is @@ -258,8 +266,8 @@ { // if page not found or page data not valid anymore, use active page to read data in pPage = UpdateActivePageL(aPos); - // read data - aDes.Copy(pPage->PtrInPage(aPos), aLength); + // read data and append them to the descriptor + aDes.Append(pPage->PtrInPage(aPos), aLength); } } @@ -305,22 +313,19 @@ dataLen -= bytesToPageEnd; currMediaPos += bytesToPageEnd; - TPtr8 dataNext = aDes.MidTPtr(aDes.Length()); - //-- 2. read whole pages of data while (dataLen >= PageSz) { //-- find out if currMediaPos is in cache. If not, find a spare page and read data there - ReadDataFromSinglePageL(currMediaPos, PageSz, dataNext); + ReadDataFromSinglePageL(currMediaPos, PageSz, aDes); currMediaPos += PageSz; dataLen -= PageSz; - dataNext = dataNext.MidTPtr(dataNext.Length()); } //-- 3. read the rest of the data if(dataLen > 0) { - ReadDataFromSinglePageL(currMediaPos, dataLen, dataNext); + ReadDataFromSinglePageL(currMediaPos, dataLen, aDes); } } //else((TUint32)aLength <= bytesToPageEnd) } @@ -372,7 +377,7 @@ } // always make writting events MRU - MakePageMRU(aPos); + DoMakePageMRU(aPos); return; } @@ -447,22 +452,35 @@ } /** -Implementation of pure virtual function. -@see MWTCacheInterface::InvalidateCache() + Invalidate the cache + @see MWTCacheInterface::InvalidateCache() */ -void CDynamicDirCache::InvalidateCache(void) +void CDynamicDirCache::DoInvalidateCache(void) { __PRINT2(_L("CDynamicDirCache::InvalidateCache(locked=%d, unlocked=%d)"), iLockedQCount, iUnlockedQCount); // we should never decommit locked pages as they needs to be reserved anyway // the overhead of unnecessary page committing operations - while(!iLockedQ.IsEmpty()) + + TInt pagesToRemoveFromLockedQueue = iLockedQCount - iPermanentlyAllocatedPageCount; + TInt n; + for (n=0; nStartPos()); // remove from lookuptable + DecommitPage(page); // inform cache client to decommit page memory delete page; } - ASSERT(iLockedQCount == 0); + ASSERT(iLockedQCount == iPermanentlyAllocatedPageCount); + + TDblQueIter q(iLockedQ); + q.SetToFirst(); + while((TDynamicDirCachePage*) q) + { + TDynamicDirCachePage* page = q++; + LookupTblRemove(page->StartPos());// remove from lookuptable + ResetPagePos(page); // reset start media position (0), invalidate page content + } // however we should decommit unlocked pages here while (!iUnlockedQ.IsEmpty()) @@ -475,26 +493,19 @@ } ASSERT(iUnlockedQCount == 0); - ASSERT(iLookupTable.Count() == 0); - iLookupTable.Close(); + ASSERT(iLockedQCount == iPermanentlyAllocatedPageCount); ASSERT(iCacheMemoryClient); - - // initialize cache state. - // Note that once the client is reset, all pages lose connection with the client - // including the active page. So we will need to reset and re-allocate active page - // properly. - if (iCacheMemoryClient) - iCacheMemoryClient->Reset(); - - // reset and re-allocate active page - ResetPagePos(iActivePage); // reset start media position (0), invalidate page content - TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs()); - // this should always succeed as the client has just been reset and there are always reserved pages - ASSERT(startRamAddr); - iActivePage->SetStartPtr(startRamAddr); // set RAM address } +/** +Implementation of pure virtual function. +@see MWTCacheInterface::InvalidateCache() +*/ +void CDynamicDirCache::InvalidateCache(void) + { + DoInvalidateCache(); + } /** this method isn't implemented*/ void CDynamicDirCache::InvalidateCachePage(TUint64 /*aPos*/) @@ -633,13 +644,10 @@ return iPageSizeLog2; } -/** -Implementation of pure virtual function. -@see MWTCacheInterface::MakePageMRU() -*/ -void CDynamicDirCache::MakePageMRU(TInt64 aPos) + +void CDynamicDirCache::DoMakePageMRU(TInt64 aPos) { - __PRINT1(_L("MakePageMRU (%lx)"), aPos); +// __PRINT1(_L("MakePageMRU (%lx)"), aPos); // __PRINT4(_L("Current Cache State: iLockedQCount=%d, iUnlockedQCount=%d, iLookupTbl=%d, iMaxSizeInPages=%d"), iLockedQCount, iUnlockedQCount, iLookupTable.Count(), iMaxSizeInPages); // check the MRU page first, if it is already the MRU page, we can return immediately TInt64 pageStartMedPos = CalcPageStartPos(aPos); @@ -689,94 +697,13 @@ // by now, the page is either locked or active page ASSERT(pPage && pPage->IsValid() && pPage->IsLocked()); + + + TBool allocateNewPage = pPage == iLockedQ.Last() && !CacheIsFull(); + + switch (pPage->PageType()) { - // if the page is the active page, we will need to find a new active page for replacement - case TDynamicDirCachePage::EActivePage: - { - TDynamicDirCachePage* newAP = NULL; - // if there is more cache room available, try to create a new page first - if (!CacheIsFull()) - { - // allocate and lock a new page - TRAPD(err, newAP = AllocateAndLockNewPageL(0)); - // if any error ocurrs, return immediately - if (err != KErrNone) - { - // unlock the page that was originally unlocked before leave - if (pPage->PageType() == TDynamicDirCachePage::EUnlocked) - { - UnlockPage(pPage); - } - return; - } - - if (newAP) - { - // replace the active page with the new page - newAP->SetPageType(TDynamicDirCachePage::EActivePage); - iActivePage = newAP; - } - } - - // if cache has grown to its max size, or new page allocation failed - if (!newAP) - { - // try to lock the LRU page on the unlocked page queque first - if (!iUnlockedQ.IsEmpty()) - { - newAP = iUnlockedQ.Last(); - ASSERT(newAP->IsValid()); - if (LockPage(newAP) != NULL) - { - // deque, reset pos, set new type - DeQueue(newAP); - LookupTblRemove(newAP->StartPos()); - ResetPagePos(newAP); - newAP->SetPageType(TDynamicDirCachePage::EActivePage); - // replace active page - iActivePage = newAP; - } - // if falied locking the LRU page from unclocked queque, - // delete it - else - { - DeQueue(newAP); - LookupTblRemove(newAP->StartPos()); - DecommitPage(newAP); - delete newAP; - newAP = NULL; - } - } - } - - // if still have not found new active page - // grab the LRU page from Locked Page Queue for active page - if (!newAP) - { - ASSERT(!iLockedQ.IsEmpty()); - newAP = iLockedQ.Last(); - // deque, reset pos, set new type - DeQueue(newAP); - LookupTblRemove(newAP->StartPos()); - ResetPagePos(newAP); - newAP->SetPageType(TDynamicDirCachePage::EActivePage); - // replace active page - iActivePage = newAP; - } - - // we should always be able to find a locked page for active page - ASSERT(newAP != NULL); - - // make original page (i.e. former active page) MRU - // add onto locked queue - AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked); - // add onto lookuptbl, as active page is not on lookup tbl originally - LookupTblAdd(pPage); - // check cache limit - CheckThresholds(); - return; - } case TDynamicDirCachePage::EUnlocked: { // if page was originally on Unlocked Page Queque, remove it from Unlocked Page Queue, add it @@ -785,7 +712,6 @@ AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked); // check cache limit CheckThresholds(); - return; } case TDynamicDirCachePage::ELocked: { @@ -795,13 +721,40 @@ { DeQueue(pPage); AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked); - return; } break; } default: ASSERT(0); } + + if (allocateNewPage) + { + TDynamicDirCachePage* nPage = NULL; + TRAPD(err, nPage = AllocateAndLockNewPageL(0)); + if (err == KErrNone) + { + + // about to add a page to end of locked queue, so lie about iLockedQCount + iLockedQCount++; + CheckThresholds(); + iLockedQCount--; + + iLockedQ.AddLast(*nPage); + nPage->SetPageType(TDynamicDirCachePage::ELocked); + ++iLockedQCount; + LookupTblAdd(nPage); + } + } + } + +/** + Implementation of pure virtual function. + @see MDiskSpecialAccessor::MakePageMRU() +*/ +void CDynamicDirCache::MakePageMRU(TInt64 aPos) + { + DoMakePageMRU(aPos); } //==================================================================== @@ -810,16 +763,10 @@ */ TDynamicDirCachePage* CDynamicDirCache::FindPageByPos(TInt64 aPos) { - __PRINT1(_L("CDynamicDirCache::FindPageByPos(aPos=%lx)"), aPos); +// __PRINT1(_L("CDynamicDirCache::FindPageByPos(aPos=%lx)"), aPos); // align the page position TInt64 pageStartMedPos = CalcPageStartPos(aPos); - if ((iActivePage->StartPos() == pageStartMedPos)) - { - ASSERT(iActivePage->IsValid()); - return iActivePage; - } - // search in lookup table return LookupTblFind(pageStartMedPos); } @@ -832,29 +779,40 @@ // align the page position TInt64 pageStartMedPos = CalcPageStartPos(aPos); - if (iActivePage->StartPos() == pageStartMedPos && iActivePage->IsValid()) + ASSERT(!iLockedQ.IsEmpty()); + TDynamicDirCachePage* activePage = iLockedQ.Last(); + + if (activePage->StartPos() == pageStartMedPos && activePage->IsValid()) { - return iActivePage; + return activePage; } - __PRINT2(_L("CDynamicDirCache::UpdateActivePageL(aPos=%lx, active=%lx)"), aPos, iActivePage->StartPos()); + __PRINT2(_L("CDynamicDirCache::UpdateActivePageL(aPos=%lx, active=%lx)"), aPos, activePage->StartPos()); + + activePage->Deque(); + LookupTblRemove(activePage->StartPos()); // set start med pos value, no other effects, only available to active page - iActivePage->SetPos(pageStartMedPos); + activePage->SetPos(pageStartMedPos); // read data, make active page valid - TUint8* data = iActivePage->PtrInPage(iActivePage->iStartMedPos); + TUint8* data = activePage->PtrInPage(activePage->iStartMedPos); TPtr8 dataPtr(data, iPageSizeInBytes); - const TInt nErr = iDrive.ReadNonCritical(iActivePage->iStartMedPos, iPageSizeInBytes, dataPtr); + + const TInt nErr = iDrive.ReadNonCritical(activePage->iStartMedPos, iPageSizeInBytes, dataPtr); + + iLockedQ.AddLast(*activePage); + LookupTblAdd(activePage); + if(nErr !=KErrNone) { // some serious problem occured during reading, invalidate cache. - InvalidateCache(); + DoInvalidateCache(); User::Leave(nErr); } - iActivePage->SetValid(ETrue); + activePage->SetValid(ETrue); - return iActivePage; + return activePage; } /** @@ -971,7 +929,7 @@ while((TDynamicDirCachePage*)q) { TDynamicDirCachePage* pP = q++; - __PRINT3(_L("=== CDynamicDirCache::iLockedQ\t[%4d](pos=%lx, size=%d)"), i++, pP->StartPos(), pP->PageSizeInBytes()); + __PRINT5(_L("=== CDynamicDirCache::iLockedQ\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes()); } } if (!iUnlockedQ.IsEmpty()) @@ -982,10 +940,9 @@ while((TDynamicDirCachePage*)q) { TDynamicDirCachePage* pP = q++; - __PRINT3(_L("=== CDynamicDirCache::iUnlockedQ\t[%4d](pos=%lx, size=%u)"), i++, pP->StartPos(), pP->PageSizeInBytes()); + __PRINT5(_L("=== CDynamicDirCache::iUnlockedQ\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes()); } } - __PRINT2(_L("=== CDynamicDirCache::iActivePage\t[*](pos=%lx, size=%u)"), iActivePage->StartPos(), iActivePage->PageSizeInBytes()); if (iLookupTable.Count()) { @@ -996,7 +953,7 @@ while(pEntry) { TDynamicDirCachePage* pP = pEntry->iPage; - __PRINT3(_L("=== CDynamicDirCache::iLookupTable\t[%4d](pos=%lx, size=%u)"), i++, pP->StartPos(), pP->PageSizeInBytes()); + __PRINT5(_L("=== CDynamicDirCache::iLookupTable\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes()); pEntry = (TLookupEntry*) iter.Next(); }; } @@ -1128,13 +1085,6 @@ if (!aPage) return KErrArgument; - // page must be dequed first or it is active page - if (aPage->iType != TDynamicDirCachePage::EActivePage && aPage->iType != TDynamicDirCachePage::EUnknown) - { - ASSERT(0); - return KErrArgument; - } - if (aType == TDynamicDirCachePage::ELocked) { iLockedQ.AddFirst(*aPage); @@ -1219,7 +1169,10 @@ TLookupEntry* entry = iLookupTable.Find(TLookupEntry(aPos, 0, NULL)); if(entry) { - ASSERT(entry->iPage->IsValid()); + // last entry on used queue is used as the 'active' page & may not be valid + if (!entry->iPage->IsValid()) + return NULL; + return entry->iPage; }