persistentstorage/sql/OsLayer/FileBuf64.cpp
changeset 35 0d6db0a14001
parent 22 a7ba600cb39d
child 41 3256212fc81f
--- a/persistentstorage/sql/OsLayer/FileBuf64.cpp	Fri Jun 11 15:29:22 2010 +0300
+++ b/persistentstorage/sql/OsLayer/FileBuf64.cpp	Tue Jul 06 16:18:30 2010 +0300
@@ -195,6 +195,7 @@
 	EFBufPanicNextReadFilePos,
 	EFBufPanicNextReadFilePosHits,
 	EFBufPanicFileBlockSize,			//15
+	EFBufPanicRwDataLength,
 	};
 
 /**
@@ -249,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);
 	}
 
 /**
@@ -473,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))
@@ -537,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;
@@ -608,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;)
@@ -1078,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
 
 /**
@@ -1093,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
 	{
@@ -1106,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