userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp
changeset 149 d9f1e5bfe28c
parent 90 947f0dc9f7a8
child 201 43365a9b78a3
--- a/userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp	Mon May 24 18:45:46 2010 +0100
+++ b/userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp	Thu Jun 10 11:48:01 2010 +0100
@@ -27,9 +27,9 @@
 The static cache page creation function.
 Cache page objects are not supposed to be created on the stack, so this factory function is required.
 */
-TDynamicDirCachePage* TDynamicDirCachePage::NewL(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
+TDynamicDirCachePage* TDynamicDirCachePage::CreateCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
 	{
-	return new(ELeave) TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr);
+	return new TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr);
 	}
 
 /**
@@ -158,7 +158,7 @@
 
 	// 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)
+	//-- At present moment the size of TDrive thread pool is 1 (1 drive thread in a pool)
 	const TUint KThreadCount = 1;
 	iPermanentlyAllocatedPageCount = KThreadCount + 1; 
 
@@ -167,7 +167,10 @@
 
 	for (TUint n=0; n<iPermanentlyAllocatedPageCount; n++)
 		{
-		TDynamicDirCachePage* pPage = AllocateAndLockNewPageL(0);
+		TDynamicDirCachePage* pPage = AllocateAndLockNewPage(0);
+		ASSERT(pPage);
+		if (!pPage)
+			User::Leave(KErrNoMemory);
 		AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
 		LookupTblAdd(pPage);
 		}
@@ -694,47 +697,46 @@
 		}
 
 	TDynamicDirCachePage* pPage = FindPageByPos(aPos);
-    if (pPage)
-    	{
-    	ASSERT(pPage->IsValid());
+	if (pPage)
+		{
+		ASSERT(pPage->IsValid());
 		// lock page before make it MRU
-    	if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
-    		{
-    		ASSERT(!pPage->IsLocked());
-        	if (LockPage(pPage) == NULL)
-        		{
-        		DeQueue(pPage);
-        		LookupTblRemove(pPage->StartPos());
-        		DecommitPage(pPage);
-        		delete pPage;
-        		pPage = NULL;
-        		}
-    		}
-    	else
-    		{
-    		// error checking: page should either be locked or active
-    		ASSERT(LockPage(pPage) != NULL);
-    		}
-    	}
+		if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
+			{
+			ASSERT(!pPage->IsLocked());
+			if (LockPage(pPage) == NULL)
+				{
+				DeQueue(pPage);
+				LookupTblRemove(pPage->StartPos());
+				DecommitPage(pPage);
+				delete pPage;
+				pPage = NULL;
+				}
+			}
+		else
+			{
+			// error checking: page should either be locked or active
+			ASSERT(LockPage(pPage) != NULL);
+			}
+		}
 
-    // if page not found or page data not valid anymore, use active page to read data
-    if (!pPage)
-    	{
-        TRAPD(err, pPage = UpdateActivePageL(aPos));
-        if (err != KErrNone)
-        	{
-        	// problem occurred reading active page, return immediately.
-        	return;
-        	}
-    	}
+	// if page not found or page data not valid anymore, use active page to read data
+	if (!pPage)
+		{
+		TRAPD(err, pPage = UpdateActivePageL(aPos));
+		if (err != KErrNone)
+			{
+			// problem occurred reading active page, return immediately.
+			return;
+			}
+		}
 
-    // by now, the page is either locked or active page
+	// by now, the page is either locked or active page
 	ASSERT(pPage && pPage->IsValid() && pPage->IsLocked());
 
 
-
-	TBool allocateNewPage = pPage == iLockedQ.Last() && !CacheIsFull();
-
+	// if we used the active page (last on the queue), try to grow the cache.
+	TBool growCache = pPage == iLockedQ.Last();
 
 	switch (pPage->PageType())
 		{
@@ -762,24 +764,24 @@
 			ASSERT(0);
 		}
 
-	if (allocateNewPage)
-		{
-		TDynamicDirCachePage* nPage = NULL;
-		TRAPD(err, nPage = AllocateAndLockNewPageL(0));
-		if (err == KErrNone)
-			{
+	if (CacheIsFull() || !growCache)
+		return;
+
+	// attempt to grow the cache by appending a clean, new page at the end of the LRU list.
+	// This can fail when out of memory; the LRU mechanism then makes sure the oldest page will be re-used.
+	TDynamicDirCachePage* nPage = AllocateAndLockNewPage(0);
+	if (!nPage)
+		return;
 
-			// about to add a page to end of locked queue, so lie about iLockedQCount
-			iLockedQCount++;
-			CheckThresholds();
-			iLockedQCount--;
+	// 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);
-			}
-		}
+	iLockedQ.AddLast(*nPage);
+	nPage->SetPageType(TDynamicDirCachePage::ELocked);
+	++iLockedQCount;
+	LookupTblAdd(nPage);
 	}
 
 /**
@@ -898,21 +900,28 @@
 @param	aStartMedPos	the starting media address of the page to be created.
 @pre	aStartMedPos should not already be existing in the cache.
 */
-TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPageL(TInt64 aStartMedPos)
+TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPage(TInt64 aStartMedPos)
 	{
-	__PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPageL(aStartMedPos=%lx)"), aStartMedPos);
+	__PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPage(aStartMedPos=%lx)"), aStartMedPos);
 
 	TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs());
-	if (startRamAddr)
+
+	if (!startRamAddr)
+		return NULL;
+
+	TDynamicDirCachePage* pPage = TDynamicDirCachePage::CreateCachePage(this, aStartMedPos, startRamAddr);
+
+	// Failure would mean the cache chunk was able to grow but we've run out of heap.
+	// This seems extremely unlikely, but decommit the now-unmanageable cache segment just in case.
+	if (!pPage)
 		{
-		// create new page and return
-		TDynamicDirCachePage* pPage = TDynamicDirCachePage::NewL(this, aStartMedPos, startRamAddr);
-		pPage->SetLocked(ETrue);
-		pPage->SetValid(EFalse);
-		return pPage;
+		iCacheMemoryClient->DecommitSegments(startRamAddr, PageSizeInSegs());
+		return NULL;
 		}
 
-	return NULL;
+	pPage->SetLocked(ETrue);
+	pPage->SetValid(EFalse);
+	return pPage;
 	}
 
 #ifdef _DEBUG