userlibandfileserver/fileserver/sfile/sf_file_cache.cpp
changeset 176 af6ec97d9189
parent 134 95847726fe57
child 254 1560c419b176
--- a/userlibandfileserver/fileserver/sfile/sf_file_cache.cpp	Wed Jun 23 11:59:44 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_file_cache.cpp	Wed Jun 23 12:52:28 2010 +0100
@@ -40,6 +40,9 @@
 // disables flushing of stale cachelines before each write
 #define LAZY_WRITE
 
+// call SetSizeL() to pre-allocate FAT clusters before flushing dirty data
+#define SETSIZE_BEFORE_WRITE	
+
 enum TFileCacheFault
 	{
 	ECacheSettingsInitFailed,
@@ -67,6 +70,7 @@
 	EUnexpectedReNewLFailure,
 	EDirtyDataOwnerNull,
 	EFlushingWithSessionNull,
+	EFlushingWithAllocatedRequest,
 	};
 
 
@@ -80,6 +84,10 @@
 
 const TInt KMinSequentialReadsBeforeReadAhead = 3;
 
+#ifdef DOUBLE_BUFFERED_WRITING
+const TInt KMinSequentialAppendsBeforeFlush = 3;
+#endif
+
 //************************************
 // CFileCache
 //************************************
@@ -989,7 +997,7 @@
 				// with any dirty data already in the file cache
 				if (aMode & EFileWriteBuffered)
 					{
-					TInt r = DoFlushDirty(aNewRequest, &aMsgRequest, ETrue);
+					TInt r = DoFlushDirty(aNewRequest, &aMsgRequest, EFlushAll);
 					if (r == CFsRequest::EReqActionBusy || r != CFsRequest::EReqActionComplete)
 						return r;
 					}
@@ -1163,13 +1171,25 @@
 					currentPos = iSize64;
 				iInitialSize = iSize64;
 
+
+#ifdef DOUBLE_BUFFERED_WRITING
+				// count the number of sequential write-appends
+				if (currentOperation->iClientRequest)
+					{
+					if (currentPos == iSize64)
+						iSequentialAppends++;
+					else
+						iSequentialAppends = 0;
+					}
+#endif // DOUBLE_BUFFERED_WRITING
+
 				// if EFileWriteDirectIO OR 
 				// (caching writes and requested write len > size of the cache), 
 				// flush the write cache
 				if ((aMode & EFileWriteBuffered) == 0 || 
 					(cachingWrites && totalLen > iCacheSize))
 					{
-					TInt r = DoFlushDirty(aNewRequest, &aMsgRequest, ETrue);
+					TInt r = DoFlushDirty(aNewRequest, &aMsgRequest, EFlushAll);
 					if (r == CFsRequest::EReqActionBusy || r != CFsRequest::EReqActionComplete)
 						return r;
 					}
@@ -1241,7 +1261,7 @@
 					// If there's nothing to flush then the dirty (locked) data
 					// must belong to another drive, so there's not much we can do
 					// but write through 
-					TInt r = DoFlushDirty(aNewRequest, &aMsgRequest, EFalse);
+					TInt r = DoFlushDirty(aNewRequest, &aMsgRequest, EFlushSingle);
 					if (r == CFsRequest::EReqActionBusy)
 						return CFsRequest::EReqActionBusy;
 					if (r != KErrInUse)
@@ -1266,11 +1286,18 @@
 					// or wait if already flushing
 					if (iFlushBusy)
 						return CFsRequest::EReqActionBusy;
-					TInt r = DoFlushDirty(aNewRequest, &aMsgRequest, EFalse);
+					TInt r = DoFlushDirty(aNewRequest, &aMsgRequest, EFlushSingle);
 					if (r != CFsRequest::EReqActionBusy && r != CFsRequest::EReqActionComplete)
 						lastError = r;
 					}
 #endif
+#ifdef DOUBLE_BUFFERED_WRITING
+				if (cachingWrites && lastError == KErrNone && 
+					iSequentialAppends >= KMinSequentialAppendsBeforeFlush && iCacheClient->LockedSegmentsHalfUsed())
+					{
+					DoFlushDirty(aNewRequest, &aMsgRequest, EFlushHalf);
+					}
+#endif
 				// if no cacheline found & write caching is enabled, allocate a new cacheline
 				if (cachingWrites && addr == NULL && lastError == KErrNone)
 					{
@@ -1499,7 +1526,7 @@
 
 				if (cachingWrites)
 					{
-					TInt r = DoFlushDirty(aNewRequest, &aMsgRequest, ETrue);
+					TInt r = DoFlushDirty(aNewRequest, &aMsgRequest, EFlushAll);
 #ifdef _DEBUG
 					if (r == CFsRequest::EReqActionBusy)
 						CCacheManagerFactory::CacheManager()->Stats().iWriteThroughWithDirtyDataCount++;
@@ -1577,7 +1604,7 @@
 
 	CFsClientMessageRequest* newRequest = NULL;
 
-	TInt r = DoFlushDirty(newRequest, aOldRequest, ETrue);
+	TInt r = DoFlushDirty(newRequest, aOldRequest, EFlushAll);
 
 	iLock.Signal();
 
@@ -1615,7 +1642,7 @@
 /**
 CFileCache::DoFlushDirty()
 
-@param aFlushAll. If EFalse then only a single cacheline will be flushed
+@param aFlushMode. The flush mode which indicates how many cache-lines to flush. @See TFlushMode
 
 returns	CFsRequest::EReqActionBusy if a flush is in progress OR cacheline already in use
 		CFsRequest::EReqActionComplete if nothing to flush / flush completed 
@@ -1623,11 +1650,13 @@
 		or one of the system wide error codes
 
  */
-TInt CFileCache::DoFlushDirty(CFsClientMessageRequest*& aNewRequest, CFsRequest* aOldRequest, TBool aFlushAll)
+TInt CFileCache::DoFlushDirty(CFsClientMessageRequest*& aNewRequest, CFsRequest* aOldRequest, TFlushMode aFlushMode)
 	{
 	TInt64  pos;
 	TUint8* addr;
 
+	__ASSERT_ALWAYS(aNewRequest == NULL, Fault(EFlushingWithAllocatedRequest));
+
 	if (iFlushBusy)
 		return CFsRequest::EReqActionBusy;
 
@@ -1681,10 +1710,8 @@
 		return r;
 		}
 
-	// set the number of segments to flush - either all dirty data or the equivalent of one full cacheline
-	aNewRequest->CurrentOperation().iScratchValue0 = 
-		(TAny*) (aFlushAll?KMaxTInt:iCacheClient->CacheLineSizeInSegments());
-
+	// set the flush mode
+	aNewRequest->CurrentOperation().iScratchValue0 = (TAny*) aFlushMode;
 
 	// issue flush request
 	r = FlushDirtySm(*aNewRequest);
@@ -1701,6 +1728,11 @@
 		}
 	else	// CFsRequest::EReqActionComplete
 		{
+		// Return any allocation failures etc to client
+		TInt lastError = aNewRequest->LastError();
+		if (lastError != KErrNone)
+			r = lastError;
+
 		aNewRequest->PopOperation();
 		aNewRequest->Free();
 		aNewRequest = NULL;
@@ -1778,9 +1810,6 @@
 				TUint8* addr;
 				TInt segmentCount = iCacheClient->FindFirstDirtySegment(pos, addr);
 				
-				// keep track of how many segments we've written
-				currentOperation->iScratchValue0 = (TAny*) ((TInt) currentOperation->iScratchValue0 - segmentCount);
-
 				// if no more dirty segments of if a genuine error then finish
 				// NB if the request has been cancelled then we still need to proceed and mark all the
 				// segments as clean, otherwise they will never get freed !
@@ -1807,6 +1836,28 @@
 					break;
 					}
 
+#ifdef SETSIZE_BEFORE_WRITE	
+				TInt64 physicalFileSize = iFileCB->Size64();
+				if ((pos + (TInt64) len) > physicalFileSize)
+					{
+					// Need to switch to drive thread before calling CFileCB::SetSizeL()
+					if (!IsDriveThread())
+						{
+						aMsgRequest.SetState(CFsRequest::EReqStatePostInitialise);
+						return CFsRequest::EReqActionBusy;
+						}
+					__CACHE_PRINT2(_L("CACHEFILE: Increasing uncached size from %ld to %ld"), iFileCB->Size64(), iSize64);
+					TInt r;
+
+					r = CheckDiskSpace(iSize64 - physicalFileSize, &aMsgRequest);
+			        if(r == KErrNone)
+						TRAP(r, iFileCB->SetSizeL(iSize64))
+					if (r == KErrNone)
+						{
+ 						iFileCB->SetSize64(iSize64, ETrue);	// NB drive might be locked
+						}
+					}
+#endif
 				__CACHE_PRINT3(_L("CACHEFILE: FlushDirty first dirty pos %d, addr %08X count %d"), I64LOW(pos), addr, segmentCount);
 
 				TInt filledSegmentCount;
@@ -1900,12 +1951,24 @@
 					}
 
 
-				if (TInt(currentOperation->iScratchValue0) > 0)
-					currentOperation->iState = EStWriteToDisk;
-				else
-					currentOperation->iState = EStEnd;
-
-
+				switch((TFlushMode) (TInt) currentOperation->iScratchValue0)
+					{
+					case EFlushSingle:
+						currentOperation->iState = EStEnd;
+						break;
+					case EFlushHalf:
+						if (iCacheClient->LockedSegmentsHalfUsed())
+							currentOperation->iState = EStWriteToDisk;
+						else
+							currentOperation->iState = EStEnd;
+						break;
+					case EFlushAll:
+						currentOperation->iState = EStWriteToDisk;
+						break;
+					default:
+						ASSERT(0);
+						break;
+					}
 				}
 				break;