diff -r 63532cdadd44 -r 0d6db0a14001 persistentstorage/sql/OsLayer/FileBuf64.cpp --- 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 (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