--- 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