persistentstorage/sql/OsLayer/FileBuf64.cpp
changeset 29 cce6680bbf1c
parent 17 55f2396f6d25
child 31 ba1c4f4a893f
--- a/persistentstorage/sql/OsLayer/FileBuf64.cpp	Fri May 14 13:32:10 2010 +0100
+++ b/persistentstorage/sql/OsLayer/FileBuf64.cpp	Thu Jul 01 17:02:22 2010 +0100
@@ -1,4 +1,4 @@
-// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
 // All rights reserved.
 // This component and the accompanying materials are made available
 // under the terms of "Eclipse Public License v1.0"
@@ -22,53 +22,98 @@
 
 extern TBool TheOsCallTimeDetailedProfileEnabled;//If true, the OS porting layer call details are enabled and for each call an entry will be added to the log file (epocwind.out).
 
-#define PROFILE_READ(pos,amount) \
+#define PROFILE_READ(pos, amount, err) \
 	do \
 		{ \
 		if(TheOsCallTimeDetailedProfileEnabled) \
 			{ \
 			++iFileReadCount; iFileReadAmount += (amount); \
-			RDebug::Print(_L(" -- FRead    this=%X, Cnt=%d, Pos=%ld, Amt=%d, Ttl=%ld\r\n"), (TUint32)this, iFileReadCount,  pos, amount, iFileReadAmount); \
+			RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Read¬%d¬%ld¬%d¬%ld¬%d\r\n"), (TUint32)this, iFileReadCount, pos, amount, iFileReadAmount, err); \
 			} \
 		} while(0)
 	
-#define PROFILE_WRITE(pos,amount) \
+#define PROFILE_WRITE(pos, amount, err) \
 	do \
 		{ \
 		if(TheOsCallTimeDetailedProfileEnabled) \
 			{ \
 			++iFileWriteCount; iFileWriteAmount += (amount); \
-			RDebug::Print(_L(" -- FWrite   this=%X, Cnt=%d, Pos=%ld, Amt=%d, Ttl=%ld\r\n"), (TUint32)this, iFileWriteCount, pos, amount, iFileWriteAmount); \
+			RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Write¬%d¬%ld¬%d¬%ld¬%d\r\n"), (TUint32)this, iFileWriteCount, pos, amount, iFileWriteAmount, err); \
 			} \
 		} while(0)
 
-#define PROFILE_SIZE() \
+#define PROFILE_SIZE(size, err) \
 	do \
 		{ \
 		if(TheOsCallTimeDetailedProfileEnabled) \
 			{ \
 			++iFileSizeCount; \
-			RDebug::Print(_L(" -- FSize    this=%X, Cnt=%d\r\n"), (TUint32)this, iFileSizeCount); \
+			RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Size¬%d¬%ld¬¬¬%d\r\n"), (TUint32)this, iFileSizeCount, size, err); \
 			} \
 		} while(0)
 
-#define PROFILE_SETSIZE() \
+#define PROFILE_SETSIZE(size, err) \
 	do \
 		{ \
 		if(TheOsCallTimeDetailedProfileEnabled) \
 			{ \
 			++iFileSetSizeCount; \
-			RDebug::Print(_L(" -- FSetSize this=%X, Cnt=%d\r\n"), (TUint32)this, iFileSetSizeCount); \
+			RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬SetSize¬%d¬%ld¬¬¬%d\r\n"), (TUint32)this, iFileSetSizeCount, size, err); \
 			} \
 		} while(0)
 
-#define PROFILE_FLUSH()	\
+#define PROFILE_FLUSH(err)	\
 	do \
 		{ \
 		if(TheOsCallTimeDetailedProfileEnabled) \
 			{ \
 			++iFileFlushCount; \
-			RDebug::Print(_L(" -- FFlush   this=%X, Cnt=%d\r\n"), (TUint32)this, iFileFlushCount); \
+			RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Flush¬%d¬¬¬¬%d\r\n"), (TUint32)this, iFileFlushCount, err); \
+			} \
+		} while(0)
+
+#define PROFILE_CREATE(fname, err) \
+	do \
+		{ \
+		if(TheOsCallTimeDetailedProfileEnabled) \
+			{ \
+			RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Create¬¬¬¬¬%d¬%S\r\n"), (TUint32)this, err, &fname); \
+			} \
+		} while(0)
+
+#define PROFILE_OPEN(fname, err) \
+	do \
+		{ \
+		if(TheOsCallTimeDetailedProfileEnabled) \
+			{ \
+			RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Open¬¬¬¬¬%d¬%S\r\n"), (TUint32)this, err, &fname); \
+			} \
+		} while(0)
+
+#define PROFILE_TEMP(fname, err) \
+	do \
+		{ \
+		if(TheOsCallTimeDetailedProfileEnabled) \
+			{ \
+			RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Temp¬¬¬¬¬%d¬%S\r\n"), (TUint32)this, err, &fname); \
+			} \
+		} while(0)
+
+#define PROFILE_ADOPT(fname, err) \
+	do \
+		{ \
+		if(TheOsCallTimeDetailedProfileEnabled) \
+			{ \
+			RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Adopt¬¬¬¬¬%d¬%S\r\n"), (TUint32)this, err, &fname); \
+			} \
+		} while(0)
+
+#define PROFILE_CLOSE() \
+	do \
+		{ \
+		if(TheOsCallTimeDetailedProfileEnabled) \
+			{ \
+			RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Close¬¬¬¬¬¬\r\n"), (TUint32)this); \
 			} \
 		} while(0)
 
@@ -80,12 +125,18 @@
 
 #else
 
-#define PROFILE_READ(pos,amount)	void(0)
-#define PROFILE_WRITE(pos,amount)	void(0)
+#define PROFILE_READ(pos,amount, err)	void(0)
+#define PROFILE_WRITE(pos,amount, err)	void(0)
 
-#define PROFILE_SIZE()			void(0)
-#define PROFILE_SETSIZE()		void(0)
-#define PROFILE_FLUSH()			void(0)
+#define PROFILE_SIZE(size, err)			void(0)
+#define PROFILE_SETSIZE(size, err)		void(0)
+#define PROFILE_FLUSH(err)				void(0)
+
+#define PROFILE_CREATE(fname, err)		void(0)
+#define PROFILE_OPEN(fname, err)		void(0)
+#define PROFILE_TEMP(fname, err)		void(0)
+#define PROFILE_ADOPT(fname, err)		void(0)
+#define PROFILE_CLOSE()					void(0)
 
 #endif//_SQLPROFILER
 
@@ -144,6 +195,7 @@
 	EFBufPanicNextReadFilePos,
 	EFBufPanicNextReadFilePosHits,
 	EFBufPanicFileBlockSize,			//15
+	EFBufPanicRwDataLength,
 	};
 
 /**
@@ -198,15 +250,16 @@
 /**
 Initializes RFileBuf64 data members with their default values.
 
-@param aSize Max file buffer size (capacity) in bytes.
+@param aMinCapacity Minimal file buffer size (capacity) in bytes.
 
-@panic FBuf64 1 In _DEBUG mode - aSize is 0 or negative.
+@panic FBuf64 1 In _DEBUG mode - aMinCapacity is 0 or negative.
 */
-RFileBuf64::RFileBuf64(TInt aSize) :
-	iCapacity(aSize),
-	iReadAheadSize(RFileBuf64::KDefaultReadAheadSize)
+RFileBuf64::RFileBuf64(TInt aMinCapacity) :
+	iCapacity(aMinCapacity),
+	iReadAheadSize(RFileBuf64::KDefaultReadAheadSize),
+	iOptimized(EFalse)
 	{
-	__FBUF64_ASSERT(aSize > 0, EFBufPanicCapacity);
+	__FBUF64_ASSERT(aMinCapacity > 0, EFBufPanicCapacity);
 	}
 
 /**
@@ -238,6 +291,7 @@
 	    {
 	    err = iFile.Create(aFs, aFileName, aFileMode);
 	    }
+	PROFILE_CREATE(aFileName, err);
 	return DoPostInit(err);
 	}
 
@@ -269,6 +323,7 @@
         {
         err = iFile.Open(aFs, aFileName, aFileMode);
         }
+	PROFILE_OPEN(aFileName, err);
     return DoPostInit(err);
 	}
 
@@ -300,6 +355,7 @@
         {
         err = iFile.Temp(aFs, aPath, aFileName, aFileMode);
         }
+	PROFILE_TEMP(aFileName, err);
     return DoPostInit(err);
 	}
 
@@ -336,6 +392,7 @@
         {
         err = iFile.AdoptFromClient(aMsg, aFsIndex, aFileIndex);
         }
+	PROFILE_ADOPT(KNullDesC, err);
     return DoPostInit(err);
 	}
 
@@ -356,6 +413,7 @@
 	iFile.Close();
 	User::Free(iBase);
 	iBase = 0;
+	PROFILE_CLOSE();
 	}
 
 /**
@@ -417,21 +475,26 @@
 	__FBUF64_ASSERT(aFilePos >= 0, EFBufPanicFilePos);
 	__FILEBUF64_INVARIANT();
 	aDes.SetLength(0);
-	//1. The output buffer max len is 0
+	//0. The output buffer max len is 0
 	if(aDes.MaxLength() == 0)
 		{
 		__FILEBUF64_INVARIANT();
 		return KErrNone;	
 		}
-	//2. Initialize the "iFileSize" if it is not initialized yet
+	//1. Initialize the "iFileSize" if it is not initialized yet
 	TInt err = DoFileSize();
 	if(err != KErrNone)
 		{
 		__FILEBUF64_INVARIANT();
 		return err;	
 		}
+	//2. Optimize the buffer capacity
+	TInt len = aDes.MaxLength();
+	if((err = DoSetCapacity(len)) != KErrNone)
+		{
+		return err;
+		}
 	//3. Too big "read" request - read directly from the file
-	TInt len = aDes.MaxLength();
 	if(len > iCapacity)
 		{
 		if((aFilePos + len) > iFilePos && aFilePos < (iFilePos + iLength))
@@ -441,7 +504,7 @@
 		if(err == KErrNone)
 			{
 			err = iFile.Read(aFilePos, aDes);
-			PROFILE_READ(aFilePos, aDes.Size());
+			PROFILE_READ(aFilePos, aDes.Size(), err);
 			}
 		__FILEBUF64_INVARIANT();
 		return err;
@@ -472,7 +535,7 @@
 				iNextReadFilePosHits = 0;
 				TPtr8 ptr2(outptr, len);
 				err = iFile.Read(aFilePos, ptr2);
-				PROFILE_READ(aFilePos, ptr2.Size());
+				PROFILE_READ(aFilePos, ptr2.Size(), err);
 				if(err == KErrNone)
 					{
 					iNextReadFilePos = aFilePos + len;
@@ -481,7 +544,7 @@
 				break;
 				}
 			//The guessed from the previous "file read" operation file pos is correct. Start reading-ahead.
-			const TInt KMaxReadFilePosHits = 8;//The max read-ahead buffer size can be up to 2^8 times the iReadAheadSize
+			const TInt KMaxReadFilePosHits = 4;//The max read-ahead buffer size can be up to 2^4 times the iReadAheadSize
 			if(iNextReadFilePosHits < KMaxReadFilePosHits)
 				{
 				++iNextReadFilePosHits;
@@ -496,7 +559,7 @@
 				}
 			TPtr8 ptr(iBase, Min(iCapacity, (len + readahead)));
 			err = iFile.Read(aFilePos, ptr);
-			PROFILE_READ(aFilePos, ptr.Size());
+			PROFILE_READ(aFilePos, ptr.Size(), err);
 			if(err == KErrNone)
 				{
 				iFilePos = aFilePos;
@@ -552,6 +615,10 @@
 		__FILEBUF64_INVARIANT();
 		return err;	
 		}
+	if((err = DoSetCapacity(aData.Length())) != KErrNone)
+		{
+		return err;
+		}
 	DoDiscardBufferedReadData();
 	const TUint8* data = aData.Ptr();
 	for(TInt len = aData.Length(); len > 0 && err == KErrNone;)
@@ -787,8 +854,8 @@
 		__FILEBUF64_INVARIANT();
 		return KErrNone;
 		}
-	PROFILE_SIZE();
 	TInt err = iFile.Size(iFileSize);
+	PROFILE_SIZE(iFileSize, err);
 	if(err != KErrNone)
 		{
 		DoDiscard();
@@ -825,8 +892,8 @@
 		{
 		iLength = aFileSize - iFilePos;
 		}
-	PROFILE_SETSIZE();
 	TInt err = iFile.SetSize(aFileSize);
+	PROFILE_SETSIZE(aFileSize, err);
 	if(err != KErrNone)
 		{
 		DoDiscard();
@@ -857,8 +924,8 @@
 		__FILEBUF64_INVARIANT();
 		return err;	
 		}
-	PROFILE_FLUSH();
 	err = iFile.Flush();
+	PROFILE_FLUSH(err);
 	if(err != KErrNone)
 		{
 		DoDiscard();
@@ -889,9 +956,9 @@
 		__FILEBUF64_INVARIANT();
 		return KErrNone;	
 		}
-	PROFILE_WRITE(iFilePos, iLength);
 	TPtrC8 data(iBase, iLength);		
 	TInt err = iFile.Write(iFilePos, data);
+	PROFILE_WRITE(iFilePos, iLength, err);
 	if(err == KErrNone)
 		{
 		iFileSize = Max(iFileSize, (iFilePos + iLength));
@@ -1022,6 +1089,64 @@
 	__FILEBUF64_INVARIANT();
 	}
 
+/**
+Sets the most appropriate buffer capacity based on the database page size.
+The function does a lazy evaluation. The first time the function is called and 
+aRwDataLength parameter is recognized to be a database or journal page size, the new (optimal)
+buffer capacity is calculated and set. All next DoSetCapacity() calls will detect that the new
+capacity is already set and will return KErrNone.
+
+@param  aRwDataLength The length of the data being read or written.
+@return KErrNone The new capacity was set successfully,
+        KErrNoMemory Out of memory.
+*/
+TInt RFileBuf64::DoSetCapacity(TInt aRwDataLength)
+	{
+	const TInt KMinPageCount = 4;//the buffer capacity should be at least (KMinPageCount * page size) 
+	                             //but not less than the original capacity.
+	const TInt KDefaultPageSize = 1024;//The journal header size is equal to 512 bytes, so it is not easy
+                                       //to detect the 512 bytes page size. 
+	
+	__FBUF64_ASSERT(aRwDataLength > 0, EFBufPanicRwDataLength);
+	__FILEBUF64_INVARIANT();
+	if(iOptimized)
+		{
+		__FILEBUF64_INVARIANT();
+		return KErrNone;
+		}
+	if((aRwDataLength & (aRwDataLength - 1)) != 0 || aRwDataLength < KDefaultPageSize)
+		{
+		__FILEBUF64_INVARIANT();
+		return KErrNone;
+		}
+	//Here: aRwDataLength is power of 2 and is bigger than the default db page size.
+	//aRwDataLength is the size of the db page.
+	const TInt pageSize = aRwDataLength;
+	TInt cnt = iCapacity / pageSize;//how many pages can fit in the buffer now
+	TInt pageCount = Max(cnt, KMinPageCount);//the number of pages that should fit in the new buffer
+	TInt newBufCapacity = pageCount * pageSize;
+	if(newBufCapacity != iCapacity)
+		{
+		TUint8* newBase = static_cast <TUint8*> (User::ReAlloc(iBase, newBufCapacity));
+		if(!newBase)
+			{
+			__FILEBUF64_INVARIANT();
+			return KErrNoMemory;
+			}
+		iBase = newBase;
+		iCapacity = newBufCapacity;
+		//Adjust the initial read-ahead size to be multiple of the page size.
+		if((iReadAheadSize % pageSize) != 0)
+			{
+			TInt q = iReadAheadSize / pageSize;
+			iReadAheadSize = q != 0 ? pageSize * q : pageSize;
+			}
+		}
+	iOptimized = ETrue;
+	__FILEBUF64_INVARIANT();
+	return KErrNone;
+	}
+
 #ifdef _DEBUG
 
 /**
@@ -1037,7 +1162,7 @@
 @panic FBuf64   6 In _DEBUG mode - null file handle (the RFile64 object is not created or already destroyed).
 @panic FBuf64  13 In _DEBUG mode - set but negative iNextReadFilePos value.
 @panic FBuf64  14 In _DEBUG mode - negative iNextReadFilePosHits value.
-@panic FBuf64  15 In _DEBUG mode - iReadAheadSize is negative or is not power of two.
+@panic FBuf64  15 In _DEBUG mode - iReadAheadSize is negative or is bigger than iCapacity.
 */
 void RFileBuf64::Invariant() const
 	{
@@ -1050,7 +1175,7 @@
 	__FBUF64_ASSERT(iFile.SubSessionHandle() != 0, EFBufPanicFileHandle);
 	__FBUF64_ASSERT(iNextReadFilePos == KNextReadFilePosNotSet || iNextReadFilePos >= 0, EFBufPanicNextReadFilePos);
 	__FBUF64_ASSERT(iNextReadFilePosHits >= 0, EFBufPanicNextReadFilePosHits);
-	__FBUF64_ASSERT(iReadAheadSize > 0 && (iReadAheadSize & (iReadAheadSize - 1)) == 0, EFBufPanicFileBlockSize);
+	__FBUF64_ASSERT(iReadAheadSize > 0, EFBufPanicFileBlockSize);
 	}
 	
 #endif