sl@0: // Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: #include "FileBuf64.h" sl@0: #include "OstTraceDefinitions.h" sl@0: #ifdef OST_TRACE_COMPILER_IN_USE sl@0: #include "FileBuf64Traces.h" sl@0: #endif sl@0: #include "SqliteTraceDef.h" sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: This constant is used for initializing the RFileBuf64::iFileSize data member and means that sl@0: the iFileSize is not yet initialized with the real file size value. sl@0: (RFileBuf64::iFileSize caches the file size value) sl@0: @internalComponent sl@0: */ sl@0: static const TInt KFileSizeNotSet = -1; sl@0: sl@0: /** sl@0: This constant is used as a default initializer for the RFileBuf64::iNextReadFilePos data member, sl@0: indicating that the "guessed" file read offset is invalid and should not be used. sl@0: @internalComponent sl@0: */ sl@0: static const TInt KNextReadFilePosNotSet = -1; sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////// FBUF INVARIANT /////////////////////////////////////////////////////////////// sl@0: ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: #ifdef _DEBUG sl@0: sl@0: #define __FILEBUF64_INVARIANT() Invariant() sl@0: sl@0: #else //_DEBUG sl@0: sl@0: #define __FILEBUF64_INVARIANT() void(0) sl@0: sl@0: #endif//_DEBUG sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: /////////////////////////// RFileBuf64 ///////////////////////////////////////////////////////////////////// sl@0: ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: Initializes RFileBuf64 data members with their default values. sl@0: sl@0: @param aSize Max file buffer size (capacity) in bytes. sl@0: sl@0: @panic Sqlite3 1 In _DEBUG mode - aSize is 0 or negative. sl@0: */ sl@0: RFileBuf64::RFileBuf64(TInt aSize) : sl@0: iCapacity(aSize), sl@0: iBase(NULL), sl@0: iReadAheadSize(RFileBuf64::KDefaultReadAheadSize) sl@0: { sl@0: SQLITE_TRACE_FBUF(OstTraceExt3(TRACE_INTERNALS, RFILEBUF64_RFILEBUF64, "FBuf;0x%X;RFileBuf64::RFileBuf64;aSize=%d;iReadAheadSize=%d", (TUint)this, aSize, iReadAheadSize)); sl@0: __ASSERT_DEBUG(aSize > 0, __SQLITEPANIC(EFBufPanicCapacity)); sl@0: } sl@0: sl@0: /** sl@0: Initializes the RFileBuf64 object and creates and opens a new file that will be accessed through RFileBuf64 public interface. sl@0: If the file already exists, an error is returned. sl@0: If the resulting path does not exist, then the operation cannot proceed and the function returns an error code. sl@0: sl@0: @param aFs The file server session. sl@0: @param aFileName The name of the file. Any path components (i.e. drive letter sl@0: or directory), which are not specified, are taken from sl@0: the session path. sl@0: @param aFileMode The mode in which the file is opened. See TFileMode for details. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: @see TFileMode sl@0: @see RFile64::Create() sl@0: sl@0: @panic Sqlite3 7 In _DEBUG mode - Invalid aFs object (null file session handle). sl@0: @panic Sqlite3 10 In _DEBUG mode - Invalid file name length (zero file name length). sl@0: */ sl@0: TInt RFileBuf64::Create(RFs& aFs, const TDesC& aFileName, TUint aFileMode) sl@0: { sl@0: __ASSERT_DEBUG(aFs.Handle() != 0, __SQLITEPANIC(EFBufPanicFsHandle)); sl@0: __ASSERT_DEBUG(aFileName.Length() > 0, __SQLITEPANIC(EFBufPanicFileNameLen)); sl@0: sl@0: TInt err = DoPreInit(); sl@0: if(err == KErrNone) sl@0: { sl@0: err = iFile.Create(aFs, aFileName, aFileMode); sl@0: } sl@0: SQLITE_TRACE_FBUF(OstTraceExt5(TRACE_INTERNALS, RFILEBUF64_CREATE, "FBuf;0x%X;RFileBuf64::Create;aFs.Handle()=0x%X;aFileName=%S;iFile.SubSessionHandle()=0x%X;err=%d", (TUint)this, (TUint)aFs.Handle(), __SQLITEPRNSTR(aFileName), (TUint)iFile.SubSessionHandle(), err)); sl@0: DoPostInit(err); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Initializes the RFileBuf64 object and opens an existing file that will be accessed through RFileBuf64 public interface. sl@0: If the file does not already exist, an error is returned. sl@0: sl@0: @param aFs The file server session. sl@0: @param aFileName The name of the file. Any path components (i.e. drive letter sl@0: or directory), which are not specified, are taken from sl@0: the session path. sl@0: @param aFileMode The mode in which the file is opened. See TFileMode for details. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: @see TFileMode sl@0: @see RFile64::Open() sl@0: sl@0: @panic Sqlite3 7 In _DEBUG mode - Invalid aFs object (null file session handle). sl@0: @panic Sqlite3 10 In _DEBUG mode - Invalid file name length (zero file name length). sl@0: */ sl@0: TInt RFileBuf64::Open(RFs& aFs, const TDesC& aFileName, TUint aFileMode) sl@0: { sl@0: __ASSERT_DEBUG(aFs.Handle() != 0, __SQLITEPANIC(EFBufPanicFsHandle)); sl@0: __ASSERT_DEBUG(aFileName.Length() > 0, __SQLITEPANIC(EFBufPanicFileNameLen)); sl@0: sl@0: TInt err = DoPreInit(); sl@0: if(err == KErrNone) sl@0: { sl@0: err = iFile.Open(aFs, aFileName, aFileMode); sl@0: } sl@0: SQLITE_TRACE_FBUF(OstTraceExt5(TRACE_INTERNALS, RFILEBUF64_OPEN, "FBuf;0x%X;RFileBuf64::Open;aFs.Handle()=0x%X;aFileName=%S;iFile.SubSessionHandle()=0x%X;err=%d", (TUint)this, (TUint)aFs.Handle(), __SQLITEPRNSTR(aFileName), (TUint)iFile.SubSessionHandle(), err)); sl@0: DoPostInit(err); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Initializes the RFileBuf64 object and creates and opens a temporary file with unique name that will be accessed through sl@0: RFileBuf64 public interface. sl@0: sl@0: @param aFs The file server session. sl@0: @param aPath The directory in which the file is created. sl@0: @param aFileName On return, contains the full path and file name of the file. sl@0: The filename is guaranteed to be unique within the directory sl@0: specified by aPath. sl@0: @param aFileMode The mode in which the file is opened. The access mode is sl@0: automatically set to EFileWrite. See TFileMode for details. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: @see TFileMode sl@0: @see RFile64::Temp() sl@0: sl@0: @panic Sqlite3 7 In _DEBUG mode - Invalid aFs object (null file session handle). sl@0: */ sl@0: TInt RFileBuf64::Temp(RFs& aFs, const TDesC& aPath, TFileName& aFileName, TUint aFileMode) sl@0: { sl@0: __ASSERT_DEBUG(aFs.Handle() != 0, __SQLITEPANIC(EFBufPanicFsHandle)); sl@0: sl@0: TInt err = DoPreInit(); sl@0: if(err == KErrNone) sl@0: { sl@0: err = iFile.Temp(aFs, aPath, aFileName, aFileMode); sl@0: } sl@0: SQLITE_TRACE_FBUF(OstTraceExt5(TRACE_INTERNALS, RFILEBUF64_TEMP, "FBuf;0x%X;RFileBuf64::Temp;aFs.Handle()=0x%X;aFileName=%S;iFile.SubSessionHandle()=0x%X;err=%d", (TUint)this, (TUint)aFs.Handle(), __SQLITEPRNSTR(aFileName), (TUint)iFile.SubSessionHandle(), err)); sl@0: DoPostInit(err); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Writes to the file the pending data (if the buffer contains pending data), closes the file and releases sl@0: the RFileBuf64 resources. sl@0: RFileBuf64::Flush() should be called before RFileBuf64::Close() to ensure that if there are pending data, they will sl@0: be written to the file and if the operation fails, the caller will be notified with an appropriate return error. sl@0: sl@0: @see RFileBuf64::Flush() sl@0: */ sl@0: void RFileBuf64::Close() sl@0: { sl@0: SQLITE_TRACE_FBUF(OstTraceExt2(TRACE_INTERNALS, RFILEBUF64_CLOSE, "FBuf;0x%X;RFileBuf64::Close;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle())); sl@0: if(iFile.SubSessionHandle() != 0 && iBase != 0) sl@0: { sl@0: (void)DoFileWrite2(); sl@0: } sl@0: iFile.Close(); sl@0: User::Free(iBase); sl@0: iBase = 0; sl@0: } sl@0: sl@0: /** sl@0: Calculates and sets optimal read-ahead buffer size. sl@0: aBlockSize and aReadRecBufSize values are retrieved by the caller from the file system. sl@0: sl@0: Initialization rules: sl@0: Rule 1: If aReadRecBufSize is positive, bigger than the default read-ahead and sl@0: a power of two then the read-ahead value will be sl@0: initialized with aReadRecBufSize (if aReadRecBufSize is less than the buffer capacity otherwise sl@0: the buffer capacity will be used as a read-ahead value). sl@0: Rule 2: If rule#1 is not applicable then the same checks, as in rule#1, are performed this time for aBlockSize. sl@0: If aBlockSize passes the checks then it will be used as a read-ahead value. sl@0: sl@0: @param aBlockSize The size of a file block in bytes sl@0: @param aReadRecBufSize The recommended buffer size for optimised reading performance sl@0: sl@0: @return The new read-ahead value sl@0: sl@0: @see TVolumeIOParamInfo sl@0: */ sl@0: TInt RFileBuf64::SetReadAheadSize(TInt aBlockSize, TInt aReadRecBufSize) sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: if((aReadRecBufSize & (aReadRecBufSize - 1)) == 0 && aReadRecBufSize > RFileBuf64::KDefaultReadAheadSize) sl@0: { sl@0: iReadAheadSize = aReadRecBufSize > iCapacity ? iCapacity : aReadRecBufSize; sl@0: } sl@0: else if((aBlockSize & (aBlockSize - 1)) == 0 && aBlockSize > RFileBuf64::KDefaultReadAheadSize) sl@0: { sl@0: iReadAheadSize = aBlockSize > iCapacity ? iCapacity : aBlockSize; sl@0: } sl@0: SQLITE_TRACE_FBUF(OstTraceExt4(TRACE_INTERNALS, RFILEBUF64_SETREADAHEADSIZE, "FBuf;0x%X;RFileBuf64::SetReadAheadSize;aBlockSize=%d;aReadRecBufSize=%d;iReadAheadSize=%d", (TUint)this, aBlockSize, aReadRecBufSize, iReadAheadSize)); sl@0: __FILEBUF64_INVARIANT(); sl@0: return iReadAheadSize; sl@0: } sl@0: sl@0: /** sl@0: Reads from the file at the specified position (aFilePos). sl@0: If the data to be read is in the buffer, then the data will be taken from the buffer. sl@0: sl@0: @param aFilePos Position of first byte to be read. This is an offset from sl@0: the start of the file. sl@0: If aPos is beyond the end of the file, the function returns sl@0: a zero length descriptor. sl@0: @param aDes Descriptor into which binary data is read. Any existing contents sl@0: are overwritten. On return, its length is set to the number of sl@0: bytes read. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: @panic Sqlite3 4 In _DEBUG mode - negative aFilePos value. sl@0: See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. sl@0: sl@0: @see RFileBuf64::Invariant() sl@0: */ sl@0: TInt RFileBuf64::Read(TInt64 aFilePos, TDes8& aDes) sl@0: { sl@0: __ASSERT_DEBUG(aFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos)); sl@0: __FILEBUF64_INVARIANT(); sl@0: aDes.SetLength(0); sl@0: //1. The output buffer max len is 0 sl@0: if(aDes.MaxLength() == 0) sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: return KErrNone; sl@0: } sl@0: //2. Initialize the "iFileSize" if it is not initialized yet sl@0: TInt err = DoFileSize(); sl@0: if(err != KErrNone) sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: return err; sl@0: } sl@0: //3. Too big "read" request - read directly from the file sl@0: TInt len = aDes.MaxLength(); sl@0: if(len > iCapacity) sl@0: { sl@0: if((aFilePos + len) > iFilePos && aFilePos < (iFilePos + iLength)) sl@0: {//Write the pending data if the iDirty flag is set, otherwise preserve the buffer content. sl@0: err = DoFileWrite1(aFilePos); sl@0: } sl@0: if(err == KErrNone) sl@0: { sl@0: err = iFile.Read(aFilePos, aDes); sl@0: SQLITE_TRACE_FBUF(OstTraceExt5(TRACE_INTERNALS, RFILEBUF64_READ1, "FBuf;0x%X;RFileBuf64::Read;TooBigRq;iFileSize=%lld;aFilePos=%lld;len=%d;err=%d", (TUint)this, iFileSize, aFilePos, len, err)); sl@0: } sl@0: __FILEBUF64_INVARIANT(); sl@0: return err; sl@0: } sl@0: //4. The requested data size is smaller than the buffer capacity sl@0: TUint8* outptr = const_cast (aDes.Ptr()); sl@0: while(len > 0 && err == KErrNone && aFilePos < iFileSize) sl@0: { sl@0: //1. If part or all of the data is in the buffer - copy the data to the target location sl@0: if(aFilePos >= iFilePos && aFilePos < (iFilePos + iLength)) sl@0: { sl@0: TInt blocklen = Min(len, (iFilePos + iLength - aFilePos)); sl@0: outptr = Mem::Copy(outptr, iBase + (aFilePos - iFilePos), blocklen); sl@0: len -= blocklen; sl@0: aFilePos += blocklen; sl@0: } sl@0: //2. Perform a read-ahead operation sl@0: else sl@0: { sl@0: //Write the pending data if the iDirty flag is set, otherwise preserve the buffer content. sl@0: err = DoFileWrite1(aFilePos); sl@0: if(err != KErrNone) sl@0: { sl@0: break; sl@0: } sl@0: if(iNextReadFilePos != aFilePos) sl@0: {//Guessed read ahead was wrong. Direct "file read" operation sl@0: iNextReadFilePosHits = 0; sl@0: TPtr8 ptr2(outptr, len); sl@0: err = iFile.Read(aFilePos, ptr2); sl@0: SQLITE_TRACE_FBUF(OstTraceExt5(TRACE_INTERNALS, RFILEBUF64_READ2, "FBuf;0x%X;RFileBuf64::Read;Read;iFileSize=%lld;aFilePos=%lld;len=%d;err=%d", (TUint)this, iFileSize, aFilePos, len, err)); sl@0: if(err == KErrNone) sl@0: { sl@0: iNextReadFilePos = aFilePos + len; sl@0: len -= ptr2.Length(); sl@0: } sl@0: break; sl@0: } sl@0: //The guessed from the previous "file read" operation file pos is correct. Start reading-ahead. sl@0: const TInt KMaxReadFilePosHits = 8;//The max read-ahead buffer size can be up to 2^8 times the iReadAheadSize sl@0: if(iNextReadFilePosHits < KMaxReadFilePosHits) sl@0: { sl@0: ++iNextReadFilePosHits; sl@0: } sl@0: TInt maxReadAhead = iReadAheadSize * (1 << iNextReadFilePosHits); sl@0: TInt align = (aFilePos + len + maxReadAhead) & (iReadAheadSize - 1); sl@0: TInt readahead = maxReadAhead - align; sl@0: if(readahead < 0) sl@0: { sl@0: // if read-ahead doesn't cross block boundary do it all sl@0: readahead = maxReadAhead; sl@0: } sl@0: TPtr8 ptr(iBase, Min(iCapacity, (len + readahead))); sl@0: err = iFile.Read(aFilePos, ptr); sl@0: SQLITE_TRACE_FBUF(OstTraceExt5(TRACE_INTERNALS, RFILEBUF64_READ3, "FBuf;0x%X;RFileBuf64::Read;ReadAhead;iFileSize=%lld;aFilePos=%lld;len=%d;err=%d", (TUint)this, iFileSize, aFilePos, ptr.MaxLength(), err)); sl@0: if(err == KErrNone) sl@0: { sl@0: iFilePos = aFilePos; sl@0: iLength = ptr.Length(); sl@0: iNextReadFilePos = iFilePos + iLength; sl@0: if(iLength == 0) sl@0: { sl@0: break; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: DoDiscard(); sl@0: } sl@0: } sl@0: } sl@0: aDes.SetLength(aDes.MaxLength() - len); sl@0: __FILEBUF64_INVARIANT(); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Writes to the file at the specified offset (aFilePos) within the file. sl@0: If certain conditions are met, the data will be stored in the buffer - no call to the file server. sl@0: sl@0: @param aFilePos The offset from the start of the file at which the first byte is written. sl@0: If a position beyond the end of the file is specified, then sl@0: the write operation begins at the end of the file. sl@0: If the position has been locked, then the write fails. sl@0: sl@0: @param aData The descriptor from which binary data is written. The function writes sl@0: the entire contents of aData to the file. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: @panic Sqlite3 4 In _DEBUG mode - negative aFilePos value. sl@0: See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. sl@0: sl@0: @see RFileBuf64::Invariant() sl@0: */ sl@0: TInt RFileBuf64::Write(TInt64 aFilePos, const TDesC8& aData) sl@0: { sl@0: __ASSERT_DEBUG(aFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos)); sl@0: __FILEBUF64_INVARIANT(); sl@0: if(aData.Length() == 0) sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: return KErrNone; sl@0: } sl@0: TInt err = DoFileSize(); sl@0: if(err != KErrNone) sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: return err; sl@0: } sl@0: DoDiscardBufferedReadData(); sl@0: const TUint8* data = aData.Ptr(); sl@0: for(TInt len = aData.Length(); len > 0 && err == KErrNone;) sl@0: { sl@0: //1. The new write pos is before the buffered file pos sl@0: if(aFilePos < iFilePos) sl@0: { sl@0: //If the new data sticks to/overlapps the old data and there is room in the buffer to move the old data sl@0: //toward the end, then the new data can be copied at the beginning of the buffer. sl@0: if((aFilePos + len) >= iFilePos && (iFilePos - aFilePos) <= (iCapacity - iLength)) sl@0: { sl@0: (void)Mem::Copy(iBase + (iFilePos - aFilePos), iBase, iLength); //Make room - move the existing data toward the end sl@0: (void)Mem::Copy(iBase, data, len); //of the buffer. Stick the new data to the old data sl@0: iLength += (iFilePos - aFilePos); sl@0: iFilePos = aFilePos; //The new file pos is associated with the buffer sl@0: iFileSize = Max(iFileSize, (iFilePos + iLength)); sl@0: len = 0; //No more new data sl@0: iDirty = ETrue; sl@0: } sl@0: else sl@0: //The "aFilePos" is too far before the "iFilePos". Write the buffer and associate the new pos with the buffer sl@0: { sl@0: err = DoFileWrite2(aFilePos); sl@0: } sl@0: } sl@0: //2. The new write pos is after the associated file pos + the data length. sl@0: else if(aFilePos > (iFilePos + iLength)) sl@0: { sl@0: if(aFilePos > iFileSize) //Beyond the end of the file sl@0: { sl@0: if((iFilePos + iLength) == iFileSize && (aFilePos - iFilePos) < iCapacity) sl@0: { //but within the buffer => extend the file with zeros. sl@0: Mem::FillZ(iBase + iLength, aFilePos - iFilePos - iLength); sl@0: iLength = aFilePos - iFilePos; sl@0: iFileSize = Max(iFileSize, (iFilePos + iLength)); sl@0: iDirty = ETrue; sl@0: } sl@0: else sl@0: //Beyond the end of the file and not in the buffer - set file size. sl@0: { sl@0: err = DoSetFileSize(aFilePos); sl@0: } sl@0: } sl@0: else sl@0: //Within the file, not in the buffer - write the buffer and associate the new file pos with the buffer sl@0: { sl@0: err = DoFileWrite2(aFilePos); sl@0: } sl@0: } sl@0: //3. The new write pos is in the buffer, but the data length is too big sl@0: // (For SQLite is OK, otherwise the whole block must be written to the file) sl@0: //4. The new write pos is in the buffer, the data entirely fits in the buffer sl@0: else sl@0: { sl@0: if(iCapacity == iLength) //The buffer is full. Write the buffer and associate the new file pos sl@0: { sl@0: err = DoFileWrite2(aFilePos); sl@0: } sl@0: if(err == KErrNone) sl@0: { sl@0: TInt amount = Min(len, (iCapacity - (aFilePos - iFilePos))); sl@0: const TUint8* end = Mem::Copy(iBase + (aFilePos - iFilePos), data, amount); sl@0: iLength = Max(iLength, (end - iBase)); sl@0: iFileSize = Max(iFileSize, (iFilePos + iLength)); sl@0: len -= amount; sl@0: data += amount; sl@0: aFilePos += amount; sl@0: iDirty = ETrue; sl@0: } sl@0: } sl@0: } sl@0: __FILEBUF64_INVARIANT(); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Gets the current file size. sl@0: sl@0: @param aFileSize On return, the size of the file in bytes. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: See RFileBuf64::Invariant() for possible panics that may occur when this method is called. sl@0: sl@0: @see RFileBuf64::Invariant() sl@0: */ sl@0: TInt RFileBuf64::Size(TInt64& aFileSize) sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: TInt err = DoFileSize(); sl@0: if(err == KErrNone) sl@0: { sl@0: aFileSize = iFileSize; sl@0: } sl@0: __FILEBUF64_INVARIANT(); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Sets the file size. sl@0: sl@0: If the size of the file is reduced, data may be lost from the end of the file. sl@0: sl@0: Note: sl@0: sl@0: 1. The current file position remains unchanged unless SetSize() reduces the size sl@0: of the file in such a way that the current file position is now beyond sl@0: the end of the file. In this case, the current file position is set to sl@0: the end of file. sl@0: sl@0: 2. If the file was not opened for writing, an error is returned. sl@0: sl@0: @param aFileSize The new size of the file, in bytes. This value must not be negative, otherwise the function raises a panic. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: @panic Sqlite3 5 In _DEBUG mode - negative aFileSize value. sl@0: See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. sl@0: sl@0: @see RFileBuf64::Invariant() sl@0: */ sl@0: TInt RFileBuf64::SetSize(TInt64 aFileSize) sl@0: { sl@0: __ASSERT_DEBUG(aFileSize >= 0, __SQLITEPANIC(EFBufPanicFileSize)); sl@0: __FILEBUF64_INVARIANT(); sl@0: return DoSetFileSize(aFileSize); sl@0: } sl@0: sl@0: /** sl@0: Locks a region within the file as defined by a range of bytes. sl@0: sl@0: @see RFile64::Lock() sl@0: sl@0: @param aFilePos Position in file from which to lock; this is the offset from the beginning of the file. sl@0: @param aLength Number of bytes to lock. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error sl@0: codes. sl@0: */ sl@0: TInt RFileBuf64::Lock(TInt64 aFilePos, TInt64 aLength) const sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: TInt err = iFile.Lock(aFilePos, aLength); sl@0: SQLITE_TRACE_FBUF(OstTraceExt5(TRACE_INTERNALS, RFILEBUF64_LOCK, "FBuf;0x%X;RFileBuf64::Lock;iFileSize=%lld;aFilePos=%lld;aLength=%lld;err=%d", (TUint)this, iFileSize, aFilePos, aLength, err)); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Unlocks a region within the file as defined by a range of bytes. sl@0: sl@0: @see RFile64::UnLock() sl@0: sl@0: @param aFilePos Position in file from which to unlock; this is the offset from the beginning of the file. sl@0: @param aLength Number of bytes to unlock. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: */ sl@0: TInt RFileBuf64::UnLock(TInt64 aFilePos, TInt64 aLength) const sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: TInt err = iFile.UnLock(aFilePos, aLength); sl@0: SQLITE_TRACE_FBUF(OstTraceExt5(TRACE_INTERNALS, RFILEBUF64_UNLOCK, "FBuf;0x%X;RFileBuf64::UnLock;iFileSize=%lld;aFilePos=%lld;aLength=%lld;err=%d", (TUint)this, iFileSize, aFilePos, aLength, err)); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Writes the pending data and then flushes the file. sl@0: sl@0: Although RFileBuf64::Close() also flushes internal buffers, it is better sl@0: to call RFileBuf64::Flush() before the file is closed. This is because Close() returns no sl@0: error information, so there is no way of telling whether the final data was sl@0: written to the file successfully or not. sl@0: sl@0: @param aFlush The caller should call this function with aResetCachedFileSize parameter set, sl@0: when the buffer file is shared between threads. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: See RFileBuf64::Invariant() for possible panics that may occur when this method is called. sl@0: sl@0: @see RFileBuf64::Invariant() sl@0: */ sl@0: TInt RFileBuf64::Flush(TBool aResetCachedFileSize /*= EFalse*/) sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: TInt err = DoFileFlush(); sl@0: if(aResetCachedFileSize && err == KErrNone) sl@0: {//Unset the iFileSize to force the file buffers used by the other threads to re-read the file size. sl@0: iFileSize = KFileSizeNotSet; sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Gets information about the drive on which this file resides. sl@0: sl@0: @param aDriveNumber On return, the drive number. sl@0: sl@0: @param aDriveInfo On return, contains information describing the drive sl@0: and the medium mounted on it. The value of TDriveInfo::iType sl@0: shows whether the drive contains media. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: See RFileBuf64::Invariant() for possible panics that may occur when this method is called. sl@0: sl@0: @see RFileBuf64::Invariant() sl@0: */ sl@0: TInt RFileBuf64::Drive(TInt& aDriveNumber, TDriveInfo& aDriveInfo) const sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: TInt err = iFile.Drive(aDriveNumber, aDriveInfo); sl@0: SQLITE_TRACE_FBUF(OstTraceExt5(TRACE_INTERNALS, RFILEBUF64_DRIVE, "FBuf;0x%X;RFileBuf64::Drive;aDriveNumber=%d;driveAtt=0x%X;mediaAtt=0x%X;err=%d", (TUint)this, aDriveNumber, (TUint)aDriveInfo.iDriveAtt, (TUint)aDriveInfo.iMediaAtt, err)); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Initializes RFileBuf64 data members with their initial values. sl@0: Allocates memory for the file buffer. sl@0: sl@0: @return KErrNone if successful, sl@0: KErrNoMemory out of memory; sl@0: */ sl@0: TInt RFileBuf64::DoPreInit() sl@0: { sl@0: DoDiscard(); sl@0: iReadAheadSize = RFileBuf64::KDefaultReadAheadSize; sl@0: iBase = static_cast (User::Alloc(iCapacity)); sl@0: return iBase ? KErrNone : KErrNoMemory; sl@0: } sl@0: sl@0: /** sl@0: Performs post-initialization of the RFileBuf64 object. sl@0: If aInitErr is not KErrNone, then the buffer memory will be released. sl@0: sl@0: @param aInitErr The result of the performed before the call RFileBuf64 initialization. sl@0: */ sl@0: void RFileBuf64::DoPostInit(TInt aInitErr) sl@0: { sl@0: if(aInitErr != KErrNone) sl@0: { sl@0: User::Free(iBase); sl@0: iBase = 0; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Discards the content of the RFileBuf64 object returning it to the state as if it has just been created. sl@0: */ sl@0: void RFileBuf64::DoDiscard() sl@0: { sl@0: iLength = 0; sl@0: iFilePos = 0; sl@0: iFileSize = KFileSizeNotSet; sl@0: iDirty = EFalse; sl@0: iNextReadFilePos = KNextReadFilePosNotSet; sl@0: iNextReadFilePosHits = 0; sl@0: } sl@0: sl@0: /** sl@0: Gets the current file size. sl@0: If iFileSize value is valid, then no call to the file server will be made. sl@0: Otherwise the file server will be called and the file size - stored (cached) in iFileSize data member for later use. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: See RFileBuf64::Invariant() for possible panics that may occur when this method is called. sl@0: sl@0: @see RFileBuf64::Invariant() sl@0: */ sl@0: TInt RFileBuf64::DoFileSize() sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: if(iFileSize != KFileSizeNotSet) sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: return KErrNone; sl@0: } sl@0: TInt err = iFile.Size(iFileSize); sl@0: SQLITE_TRACE_FBUF(OstTraceExt3(TRACE_INTERNALS, RFILEBUF64_DOFILESIZE, "FBuf;0x%X;RFileBuf64::DoFileSize;iFileSize=%lld;err=%d", (TUint)this, iFileSize, err)); sl@0: if(err != KErrNone) sl@0: { sl@0: DoDiscard(); sl@0: } sl@0: __FILEBUF64_INVARIANT(); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Sets the file size. sl@0: If the buffer contains pending data, the data will be written to the file sl@0: before the "set file size" operation, if certain conditions are met. sl@0: sl@0: @param aFileSize The new size of the file, in bytes. This value must not be negative, otherwise the function raises a panic. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: @panic Sqlite3 5 In _DEBUG mode - negative aFileSize value. sl@0: See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. sl@0: sl@0: @see RFileBuf64::Invariant() sl@0: */ sl@0: TInt RFileBuf64::DoSetFileSize(TInt64 aFileSize) sl@0: { sl@0: __ASSERT_DEBUG(aFileSize >= 0, __SQLITEPANIC(EFBufPanicFileSize)); sl@0: __FILEBUF64_INVARIANT(); sl@0: if(aFileSize < iFilePos) sl@0: { sl@0: iDirty = EFalse; sl@0: iLength = 0; sl@0: } sl@0: //If the new file size is "in" the buffer then change the "iLength" sl@0: else if(aFileSize < (iFilePos + iLength)) sl@0: { sl@0: iLength = aFileSize - iFilePos; sl@0: } sl@0: TInt err = iFile.SetSize(aFileSize); sl@0: SQLITE_TRACE_FBUF(OstTraceExt4(TRACE_INTERNALS, RFILEBUF64_DOSETFILESIZE, "FBuf;0x%X;RFileBuf64::DoSetFileSize;iFileSize=%lld;aFileSize=%lld;err=%d", (TUint)this, iFileSize, aFileSize, err)); sl@0: if(err != KErrNone) sl@0: { sl@0: DoDiscard(); sl@0: } sl@0: else sl@0: { sl@0: iFileSize = aFileSize; sl@0: } sl@0: __FILEBUF64_INVARIANT(); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Writes the pending data and flushes the file. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: See RFileBuf64::Invariant() for possible panics that may occur when this method is called. sl@0: sl@0: @see RFileBuf64::Invariant() sl@0: */ sl@0: TInt RFileBuf64::DoFileFlush() sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: TInt err = DoFileWrite2();//Write the buffer if the iDirty flag is set. Do not preserve the buffer content and file pos. sl@0: if(err != KErrNone) sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: return err; sl@0: } sl@0: err = iFile.Flush(); sl@0: SQLITE_TRACE_FBUF(OstTraceExt3(TRACE_INTERNALS, RFILEBUF64_DOFILEFLUSH, "FBuf;0x%X;RFileBuf64::DoFileFlush;iFileSize=%lld;err=%d", (TUint)this, iFileSize, err)); sl@0: if(err != KErrNone) sl@0: { sl@0: DoDiscard(); sl@0: } sl@0: iLength = 0; sl@0: __FILEBUF64_INVARIANT(); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Writes the buffered data to the file if the iLength value is > 0. sl@0: If the file write operation extends the file, the iFileSize data member will be initialized with the new file size. sl@0: No changes occur in the other data member values. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. sl@0: sl@0: @see RFileBuf64::DoFileWrite1() sl@0: @see RFileBuf64::DoFileWrite2() sl@0: @see RFileBuf64::Invariant() sl@0: */ sl@0: TInt RFileBuf64::DoFileWrite() sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: if(iLength == 0) sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: return KErrNone; sl@0: } sl@0: TPtrC8 data(iBase, iLength); sl@0: TInt err = iFile.Write(iFilePos, data); sl@0: SQLITE_TRACE_FBUF(OstTraceExt5(TRACE_INTERNALS, RFILEBUF64_DOFILEWRITE, "FBuf;0x%X;RFileBuf64::DoFileWrite;iFileSize=%lld;iFilePos=%lld;iLength=%d;err=%d", (TUint)this, iFileSize, iFilePos, iLength, err)); sl@0: if(err == KErrNone) sl@0: { sl@0: iFileSize = Max(iFileSize, (iFilePos + iLength)); sl@0: } sl@0: else sl@0: { sl@0: DoDiscard(); sl@0: } sl@0: __FILEBUF64_INVARIANT(); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: Writes the buffered data to the file if the iDirty flag is set. sl@0: If the iDirty flag is set and the file write operation was successful, the iFilePos will be initialized with sl@0: the aNewFilePos value, the iLength will be set to 0. sl@0: This method is called from RFileBuf64::Read(), where: sl@0: - if the buffer contains cached writes (iDirty flag is set), the buffer has to be flushed and iFilePos initialized sl@0: with aNewFilePos - the offset in the file where the next file read operation should start from; sl@0: - if the buffer contains cached reads, then nothing happens, the buffer content will be kept; sl@0: The function resets the iDirty flag. sl@0: sl@0: @param aNewFilePos If the buffer is successfully written to the file the iFilePos data member will be initialized with sl@0: the aNewFilePos value. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. sl@0: sl@0: @panic Sqlite3 4 In _DEBUG mode - negative aNewFilePos value. sl@0: sl@0: @see RFileBuf64::Read() sl@0: @see RFileBuf64::DoFileWrite() sl@0: @see RFileBuf64::DoFileWrite2() sl@0: @see RFileBuf64::Invariant() sl@0: */ sl@0: TInt RFileBuf64::DoFileWrite1(TInt64 aNewFilePos) sl@0: { sl@0: __ASSERT_DEBUG(aNewFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos)); sl@0: __FILEBUF64_INVARIANT(); sl@0: TInt err = KErrNone; sl@0: if(iDirty) sl@0: { sl@0: err = DoFileWrite(); sl@0: if(err == KErrNone) sl@0: { sl@0: iFilePos = aNewFilePos; sl@0: iLength = 0; sl@0: } sl@0: } sl@0: iDirty = EFalse; sl@0: __FILEBUF64_INVARIANT(); sl@0: return err; sl@0: } sl@0: sl@0: /* sl@0: Writes the buffered data to the file if the iDirty flag is set. sl@0: If the file write operation was successful or if the iDirty flag was not set, the iFilePos will be initialized with sl@0: the aNewFilePos value, the iLength will be set to 0. sl@0: This method is called from RFileBuf64::Write() an other RFileBuf64 methods (but not from RFileBuf64::Read()), where: sl@0: - if the buffer contains cached writes (iDirty flag is set), the buffer has to be flushed and iFilePos initialized sl@0: with aNewFilePos - the offset in the file for which the write data will be cached in the buffer; sl@0: - if the buffer contains cached reads, then the buffer content will be destroyed, iFilePos initialized with aNewFilePos sl@0: and iLength set to 0; sl@0: The function resets the iDirty flag. sl@0: The difference between RFileBuf64::DoFileWrite1() and RFileBuf64::DoFileWrite2() is: sl@0: - RFileBuf64::DoFileWrite1() perserves the buffer content if iDirty is not set; sl@0: - RFileBuf64::DoFileWrite2() always destroys the buffer content and initializes iFilePos; sl@0: sl@0: @param aNewFilePos If the buffer is successfully written to the file the iFilePos data member will be initialized with sl@0: the aNewFilePos value. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes. sl@0: sl@0: See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. sl@0: sl@0: @panic Sqlite3 4 In _DEBUG mode - negative aNewFilePos value. sl@0: sl@0: @see RFileBuf64::Write() sl@0: @see RFileBuf64::DoFileWrite() sl@0: @see RFileBuf64::DoFileWrite1() sl@0: @see RFileBuf64::Invariant() sl@0: */ sl@0: TInt RFileBuf64::DoFileWrite2(TInt64 aNewFilePos) sl@0: { sl@0: __ASSERT_DEBUG(aNewFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos)); sl@0: __FILEBUF64_INVARIANT(); sl@0: TInt err = KErrNone; sl@0: if(iDirty) sl@0: { sl@0: err = DoFileWrite(); sl@0: } sl@0: if(err == KErrNone) sl@0: { sl@0: iFilePos = aNewFilePos; sl@0: iLength = 0; sl@0: } sl@0: iDirty = EFalse; sl@0: __FILEBUF64_INVARIANT(); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: This function discards the buffer content if the buffer contains cached read data. sl@0: The function is called from RFileBuf64::Write(), because if the buffer contains cached read data, sl@0: they cannot be mixed with the cached write data. sl@0: Reason: for example the buffer contains 8Kb cached read data from file offset 0. sl@0: The data write request is 10 bytes at offset 4000. The write data will be cached, sl@0: because the buffer contains data from from this file area: [0..8192]. sl@0: The iDirty flag will be set. Later when RFileBuf64::Flush() is called, the whole sl@0: 8Kb buffer will be written. There is nothing wrong with that, the file content will be consistent. sl@0: But from performance point of view: 8Kb written vs. 10 bytes written - that may badly impact the performance. sl@0: sl@0: @see RFileBuf64::Write() sl@0: sl@0: See RFileBuf64::Invariant() for other possible panics that may occur when this method is called. sl@0: */ sl@0: void RFileBuf64::DoDiscardBufferedReadData() sl@0: { sl@0: __FILEBUF64_INVARIANT(); sl@0: if(!iDirty && iLength > 0) sl@0: { sl@0: iLength = 0; sl@0: iFilePos = 0; sl@0: iNextReadFilePos = KNextReadFilePosNotSet; sl@0: iNextReadFilePosHits = 0; sl@0: } sl@0: __FILEBUF64_INVARIANT(); sl@0: } sl@0: sl@0: #ifdef _DEBUG sl@0: sl@0: /** sl@0: RFileBuf64 invariant. Called in _DEBUG mode at the beginning and before the end of every RFileBuf64 method sl@0: (except the init/destroy methods). sl@0: sl@0: @panic Sqlite3 11 In _DEBUG mode - null "this" pointer. sl@0: @panic Sqlite3 1 In _DEBUG mode - negative iCapacity value. sl@0: @panic Sqlite3 2 In _DEBUG mode - the buffer pointer is null (possible the buffer is not allocated or already destroyed). sl@0: @panic Sqlite3 3 In _DEBUG mode - invalid iLength value (negative or bigger than iCapacity). sl@0: @panic Sqlite3 4 In _DEBUG mode - negative iFilePos value. sl@0: @panic Sqlite3 5 In _DEBUG mode - set but negative iFileSize value. sl@0: @panic Sqlite3 6 In _DEBUG mode - null file handle (the RFile64 object is not created or already destroyed). sl@0: @panic Sqlite3 13 In _DEBUG mode - set but negative iNextReadFilePos value. sl@0: @panic Sqlite3 14 In _DEBUG mode - negative iNextReadFilePosHits value. sl@0: @panic Sqlite3 15 In _DEBUG mode - iReadAheadSize is negative or is not power of two. sl@0: */ sl@0: void RFileBuf64::Invariant() const sl@0: { sl@0: __ASSERT_DEBUG(this != 0, __SQLITEPANIC(EFBufPanicNullThis)); sl@0: __ASSERT_DEBUG(iCapacity > 0, __SQLITEPANIC(EFBufPanicCapacity)); sl@0: __ASSERT_DEBUG(iBase != 0, __SQLITEPANIC(EFBufPanicNullBuf)); sl@0: __ASSERT_DEBUG(iLength >= 0 && iLength <= iCapacity, __SQLITEPANIC(EFBufPanicBufLen)); sl@0: __ASSERT_DEBUG(iFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos)); sl@0: __ASSERT_DEBUG(iFileSize == KFileSizeNotSet || iFileSize >= 0, __SQLITEPANIC(EFBufPanicFileSize)); sl@0: __ASSERT_DEBUG(iFile.SubSessionHandle() != 0, __SQLITEPANIC(EFBufPanicFileHandle)); sl@0: __ASSERT_DEBUG(iNextReadFilePos == KNextReadFilePosNotSet || iNextReadFilePos >= 0, __SQLITEPANIC(EFBufPanicNextReadFilePos)); sl@0: __ASSERT_DEBUG(iNextReadFilePosHits >= 0, __SQLITEPANIC(EFBufPanicNextReadFilePosHits)); sl@0: __ASSERT_DEBUG(iReadAheadSize > 0 && (iReadAheadSize & (iReadAheadSize - 1)) == 0, __SQLITEPANIC(EFBufPanicFileBlockSize)); sl@0: } sl@0: sl@0: #endif