1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sqlite3api/OsLayer/FileBuf64.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,931 @@
1.4 +// Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +#include "FileBuf64.h"
1.19 +#include "OstTraceDefinitions.h"
1.20 +#ifdef OST_TRACE_COMPILER_IN_USE
1.21 +#include "FileBuf64Traces.h"
1.22 +#endif
1.23 +#include "SqliteTraceDef.h"
1.24 +
1.25 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.26 +
1.27 +/**
1.28 +This constant is used for initializing the RFileBuf64::iFileSize data member and means that
1.29 +the iFileSize is not yet initialized with the real file size value.
1.30 +(RFileBuf64::iFileSize caches the file size value)
1.31 +@internalComponent
1.32 +*/
1.33 +static const TInt KFileSizeNotSet = -1;
1.34 +
1.35 +/**
1.36 +This constant is used as a default initializer for the RFileBuf64::iNextReadFilePos data member,
1.37 +indicating that the "guessed" file read offset is invalid and should not be used.
1.38 +@internalComponent
1.39 +*/
1.40 +static const TInt KNextReadFilePosNotSet = -1;
1.41 +
1.42 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.43 +/////////////////////////// FBUF INVARIANT ///////////////////////////////////////////////////////////////
1.44 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.45 +
1.46 +#ifdef _DEBUG
1.47 +
1.48 +#define __FILEBUF64_INVARIANT() Invariant()
1.49 +
1.50 +#else //_DEBUG
1.51 +
1.52 +#define __FILEBUF64_INVARIANT() void(0)
1.53 +
1.54 +#endif//_DEBUG
1.55 +
1.56 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.57 +/////////////////////////// RFileBuf64 /////////////////////////////////////////////////////////////////////
1.58 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.59 +
1.60 +/**
1.61 +Initializes RFileBuf64 data members with their default values.
1.62 +
1.63 +@param aSize Max file buffer size (capacity) in bytes.
1.64 +
1.65 +@panic Sqlite3 1 In _DEBUG mode - aSize is 0 or negative.
1.66 +*/
1.67 +RFileBuf64::RFileBuf64(TInt aSize) :
1.68 + iCapacity(aSize),
1.69 + iBase(NULL),
1.70 + iReadAheadSize(RFileBuf64::KDefaultReadAheadSize)
1.71 + {
1.72 + SQLITE_TRACE_FBUF(OstTraceExt3(TRACE_INTERNALS, RFILEBUF64_RFILEBUF64, "FBuf;0x%X;RFileBuf64::RFileBuf64;aSize=%d;iReadAheadSize=%d", (TUint)this, aSize, iReadAheadSize));
1.73 + __ASSERT_DEBUG(aSize > 0, __SQLITEPANIC(EFBufPanicCapacity));
1.74 + }
1.75 +
1.76 +/**
1.77 +Initializes the RFileBuf64 object and creates and opens a new file that will be accessed through RFileBuf64 public interface.
1.78 +If the file already exists, an error is returned.
1.79 +If the resulting path does not exist, then the operation cannot proceed and the function returns an error code.
1.80 +
1.81 +@param aFs The file server session.
1.82 +@param aFileName The name of the file. Any path components (i.e. drive letter
1.83 + or directory), which are not specified, are taken from
1.84 + the session path.
1.85 +@param aFileMode The mode in which the file is opened. See TFileMode for details.
1.86 +
1.87 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.88 +
1.89 +@see TFileMode
1.90 +@see RFile64::Create()
1.91 +
1.92 +@panic Sqlite3 7 In _DEBUG mode - Invalid aFs object (null file session handle).
1.93 +@panic Sqlite3 10 In _DEBUG mode - Invalid file name length (zero file name length).
1.94 +*/
1.95 +TInt RFileBuf64::Create(RFs& aFs, const TDesC& aFileName, TUint aFileMode)
1.96 + {
1.97 + __ASSERT_DEBUG(aFs.Handle() != 0, __SQLITEPANIC(EFBufPanicFsHandle));
1.98 + __ASSERT_DEBUG(aFileName.Length() > 0, __SQLITEPANIC(EFBufPanicFileNameLen));
1.99 +
1.100 + TInt err = DoPreInit();
1.101 + if(err == KErrNone)
1.102 + {
1.103 + err = iFile.Create(aFs, aFileName, aFileMode);
1.104 + }
1.105 + 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));
1.106 + DoPostInit(err);
1.107 + return err;
1.108 + }
1.109 +
1.110 +/**
1.111 +Initializes the RFileBuf64 object and opens an existing file that will be accessed through RFileBuf64 public interface.
1.112 +If the file does not already exist, an error is returned.
1.113 +
1.114 +@param aFs The file server session.
1.115 +@param aFileName The name of the file. Any path components (i.e. drive letter
1.116 + or directory), which are not specified, are taken from
1.117 + the session path.
1.118 +@param aFileMode The mode in which the file is opened. See TFileMode for details.
1.119 +
1.120 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.121 +
1.122 +@see TFileMode
1.123 +@see RFile64::Open()
1.124 +
1.125 +@panic Sqlite3 7 In _DEBUG mode - Invalid aFs object (null file session handle).
1.126 +@panic Sqlite3 10 In _DEBUG mode - Invalid file name length (zero file name length).
1.127 +*/
1.128 +TInt RFileBuf64::Open(RFs& aFs, const TDesC& aFileName, TUint aFileMode)
1.129 + {
1.130 + __ASSERT_DEBUG(aFs.Handle() != 0, __SQLITEPANIC(EFBufPanicFsHandle));
1.131 + __ASSERT_DEBUG(aFileName.Length() > 0, __SQLITEPANIC(EFBufPanicFileNameLen));
1.132 +
1.133 + TInt err = DoPreInit();
1.134 + if(err == KErrNone)
1.135 + {
1.136 + err = iFile.Open(aFs, aFileName, aFileMode);
1.137 + }
1.138 + 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));
1.139 + DoPostInit(err);
1.140 + return err;
1.141 + }
1.142 +
1.143 +/**
1.144 +Initializes the RFileBuf64 object and creates and opens a temporary file with unique name that will be accessed through
1.145 +RFileBuf64 public interface.
1.146 +
1.147 +@param aFs The file server session.
1.148 +@param aPath The directory in which the file is created.
1.149 +@param aFileName On return, contains the full path and file name of the file.
1.150 + The filename is guaranteed to be unique within the directory
1.151 + specified by aPath.
1.152 +@param aFileMode The mode in which the file is opened. The access mode is
1.153 + automatically set to EFileWrite. See TFileMode for details.
1.154 +
1.155 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.156 +
1.157 +@see TFileMode
1.158 +@see RFile64::Temp()
1.159 +
1.160 +@panic Sqlite3 7 In _DEBUG mode - Invalid aFs object (null file session handle).
1.161 +*/
1.162 +TInt RFileBuf64::Temp(RFs& aFs, const TDesC& aPath, TFileName& aFileName, TUint aFileMode)
1.163 + {
1.164 + __ASSERT_DEBUG(aFs.Handle() != 0, __SQLITEPANIC(EFBufPanicFsHandle));
1.165 +
1.166 + TInt err = DoPreInit();
1.167 + if(err == KErrNone)
1.168 + {
1.169 + err = iFile.Temp(aFs, aPath, aFileName, aFileMode);
1.170 + }
1.171 + 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));
1.172 + DoPostInit(err);
1.173 + return err;
1.174 + }
1.175 +
1.176 +/**
1.177 +Writes to the file the pending data (if the buffer contains pending data), closes the file and releases
1.178 +the RFileBuf64 resources.
1.179 +RFileBuf64::Flush() should be called before RFileBuf64::Close() to ensure that if there are pending data, they will
1.180 +be written to the file and if the operation fails, the caller will be notified with an appropriate return error.
1.181 +
1.182 +@see RFileBuf64::Flush()
1.183 +*/
1.184 +void RFileBuf64::Close()
1.185 + {
1.186 + SQLITE_TRACE_FBUF(OstTraceExt2(TRACE_INTERNALS, RFILEBUF64_CLOSE, "FBuf;0x%X;RFileBuf64::Close;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
1.187 + if(iFile.SubSessionHandle() != 0 && iBase != 0)
1.188 + {
1.189 + (void)DoFileWrite2();
1.190 + }
1.191 + iFile.Close();
1.192 + User::Free(iBase);
1.193 + iBase = 0;
1.194 + }
1.195 +
1.196 +/**
1.197 +Calculates and sets optimal read-ahead buffer size.
1.198 +aBlockSize and aReadRecBufSize values are retrieved by the caller from the file system.
1.199 +
1.200 +Initialization rules:
1.201 +Rule 1: If aReadRecBufSize is positive, bigger than the default read-ahead and
1.202 + a power of two then the read-ahead value will be
1.203 + initialized with aReadRecBufSize (if aReadRecBufSize is less than the buffer capacity otherwise
1.204 + the buffer capacity will be used as a read-ahead value).
1.205 +Rule 2: If rule#1 is not applicable then the same checks, as in rule#1, are performed this time for aBlockSize.
1.206 + If aBlockSize passes the checks then it will be used as a read-ahead value.
1.207 +
1.208 +@param aBlockSize The size of a file block in bytes
1.209 +@param aReadRecBufSize The recommended buffer size for optimised reading performance
1.210 +
1.211 +@return The new read-ahead value
1.212 +
1.213 +@see TVolumeIOParamInfo
1.214 +*/
1.215 +TInt RFileBuf64::SetReadAheadSize(TInt aBlockSize, TInt aReadRecBufSize)
1.216 + {
1.217 + __FILEBUF64_INVARIANT();
1.218 + if((aReadRecBufSize & (aReadRecBufSize - 1)) == 0 && aReadRecBufSize > RFileBuf64::KDefaultReadAheadSize)
1.219 + {
1.220 + iReadAheadSize = aReadRecBufSize > iCapacity ? iCapacity : aReadRecBufSize;
1.221 + }
1.222 + else if((aBlockSize & (aBlockSize - 1)) == 0 && aBlockSize > RFileBuf64::KDefaultReadAheadSize)
1.223 + {
1.224 + iReadAheadSize = aBlockSize > iCapacity ? iCapacity : aBlockSize;
1.225 + }
1.226 + SQLITE_TRACE_FBUF(OstTraceExt4(TRACE_INTERNALS, RFILEBUF64_SETREADAHEADSIZE, "FBuf;0x%X;RFileBuf64::SetReadAheadSize;aBlockSize=%d;aReadRecBufSize=%d;iReadAheadSize=%d", (TUint)this, aBlockSize, aReadRecBufSize, iReadAheadSize));
1.227 + __FILEBUF64_INVARIANT();
1.228 + return iReadAheadSize;
1.229 + }
1.230 +
1.231 +/**
1.232 +Reads from the file at the specified position (aFilePos).
1.233 +If the data to be read is in the buffer, then the data will be taken from the buffer.
1.234 +
1.235 +@param aFilePos Position of first byte to be read. This is an offset from
1.236 + the start of the file.
1.237 + If aPos is beyond the end of the file, the function returns
1.238 + a zero length descriptor.
1.239 +@param aDes Descriptor into which binary data is read. Any existing contents
1.240 + are overwritten. On return, its length is set to the number of
1.241 + bytes read.
1.242 +
1.243 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.244 +
1.245 +@panic Sqlite3 4 In _DEBUG mode - negative aFilePos value.
1.246 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.247 +
1.248 +@see RFileBuf64::Invariant()
1.249 +*/
1.250 +TInt RFileBuf64::Read(TInt64 aFilePos, TDes8& aDes)
1.251 + {
1.252 + __ASSERT_DEBUG(aFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos));
1.253 + __FILEBUF64_INVARIANT();
1.254 + aDes.SetLength(0);
1.255 + //1. The output buffer max len is 0
1.256 + if(aDes.MaxLength() == 0)
1.257 + {
1.258 + __FILEBUF64_INVARIANT();
1.259 + return KErrNone;
1.260 + }
1.261 + //2. Initialize the "iFileSize" if it is not initialized yet
1.262 + TInt err = DoFileSize();
1.263 + if(err != KErrNone)
1.264 + {
1.265 + __FILEBUF64_INVARIANT();
1.266 + return err;
1.267 + }
1.268 + //3. Too big "read" request - read directly from the file
1.269 + TInt len = aDes.MaxLength();
1.270 + if(len > iCapacity)
1.271 + {
1.272 + if((aFilePos + len) > iFilePos && aFilePos < (iFilePos + iLength))
1.273 + {//Write the pending data if the iDirty flag is set, otherwise preserve the buffer content.
1.274 + err = DoFileWrite1(aFilePos);
1.275 + }
1.276 + if(err == KErrNone)
1.277 + {
1.278 + err = iFile.Read(aFilePos, aDes);
1.279 + 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));
1.280 + }
1.281 + __FILEBUF64_INVARIANT();
1.282 + return err;
1.283 + }
1.284 + //4. The requested data size is smaller than the buffer capacity
1.285 + TUint8* outptr = const_cast <TUint8*> (aDes.Ptr());
1.286 + while(len > 0 && err == KErrNone && aFilePos < iFileSize)
1.287 + {
1.288 + //1. If part or all of the data is in the buffer - copy the data to the target location
1.289 + if(aFilePos >= iFilePos && aFilePos < (iFilePos + iLength))
1.290 + {
1.291 + TInt blocklen = Min(len, (iFilePos + iLength - aFilePos));
1.292 + outptr = Mem::Copy(outptr, iBase + (aFilePos - iFilePos), blocklen);
1.293 + len -= blocklen;
1.294 + aFilePos += blocklen;
1.295 + }
1.296 + //2. Perform a read-ahead operation
1.297 + else
1.298 + {
1.299 + //Write the pending data if the iDirty flag is set, otherwise preserve the buffer content.
1.300 + err = DoFileWrite1(aFilePos);
1.301 + if(err != KErrNone)
1.302 + {
1.303 + break;
1.304 + }
1.305 + if(iNextReadFilePos != aFilePos)
1.306 + {//Guessed read ahead was wrong. Direct "file read" operation
1.307 + iNextReadFilePosHits = 0;
1.308 + TPtr8 ptr2(outptr, len);
1.309 + err = iFile.Read(aFilePos, ptr2);
1.310 + 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));
1.311 + if(err == KErrNone)
1.312 + {
1.313 + iNextReadFilePos = aFilePos + len;
1.314 + len -= ptr2.Length();
1.315 + }
1.316 + break;
1.317 + }
1.318 + //The guessed from the previous "file read" operation file pos is correct. Start reading-ahead.
1.319 + const TInt KMaxReadFilePosHits = 8;//The max read-ahead buffer size can be up to 2^8 times the iReadAheadSize
1.320 + if(iNextReadFilePosHits < KMaxReadFilePosHits)
1.321 + {
1.322 + ++iNextReadFilePosHits;
1.323 + }
1.324 + TInt maxReadAhead = iReadAheadSize * (1 << iNextReadFilePosHits);
1.325 + TInt align = (aFilePos + len + maxReadAhead) & (iReadAheadSize - 1);
1.326 + TInt readahead = maxReadAhead - align;
1.327 + if(readahead < 0)
1.328 + {
1.329 + // if read-ahead doesn't cross block boundary do it all
1.330 + readahead = maxReadAhead;
1.331 + }
1.332 + TPtr8 ptr(iBase, Min(iCapacity, (len + readahead)));
1.333 + err = iFile.Read(aFilePos, ptr);
1.334 + 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));
1.335 + if(err == KErrNone)
1.336 + {
1.337 + iFilePos = aFilePos;
1.338 + iLength = ptr.Length();
1.339 + iNextReadFilePos = iFilePos + iLength;
1.340 + if(iLength == 0)
1.341 + {
1.342 + break;
1.343 + }
1.344 + }
1.345 + else
1.346 + {
1.347 + DoDiscard();
1.348 + }
1.349 + }
1.350 + }
1.351 + aDes.SetLength(aDes.MaxLength() - len);
1.352 + __FILEBUF64_INVARIANT();
1.353 + return err;
1.354 + }
1.355 +
1.356 +/**
1.357 +Writes to the file at the specified offset (aFilePos) within the file.
1.358 +If certain conditions are met, the data will be stored in the buffer - no call to the file server.
1.359 +
1.360 +@param aFilePos The offset from the start of the file at which the first byte is written.
1.361 + If a position beyond the end of the file is specified, then
1.362 + the write operation begins at the end of the file.
1.363 + If the position has been locked, then the write fails.
1.364 +
1.365 +@param aData The descriptor from which binary data is written. The function writes
1.366 + the entire contents of aData to the file.
1.367 +
1.368 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.369 +
1.370 +@panic Sqlite3 4 In _DEBUG mode - negative aFilePos value.
1.371 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.372 +
1.373 +@see RFileBuf64::Invariant()
1.374 +*/
1.375 +TInt RFileBuf64::Write(TInt64 aFilePos, const TDesC8& aData)
1.376 + {
1.377 + __ASSERT_DEBUG(aFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos));
1.378 + __FILEBUF64_INVARIANT();
1.379 + if(aData.Length() == 0)
1.380 + {
1.381 + __FILEBUF64_INVARIANT();
1.382 + return KErrNone;
1.383 + }
1.384 + TInt err = DoFileSize();
1.385 + if(err != KErrNone)
1.386 + {
1.387 + __FILEBUF64_INVARIANT();
1.388 + return err;
1.389 + }
1.390 + DoDiscardBufferedReadData();
1.391 + const TUint8* data = aData.Ptr();
1.392 + for(TInt len = aData.Length(); len > 0 && err == KErrNone;)
1.393 + {
1.394 + //1. The new write pos is before the buffered file pos
1.395 + if(aFilePos < iFilePos)
1.396 + {
1.397 + //If the new data sticks to/overlapps the old data and there is room in the buffer to move the old data
1.398 + //toward the end, then the new data can be copied at the beginning of the buffer.
1.399 + if((aFilePos + len) >= iFilePos && (iFilePos - aFilePos) <= (iCapacity - iLength))
1.400 + {
1.401 + (void)Mem::Copy(iBase + (iFilePos - aFilePos), iBase, iLength); //Make room - move the existing data toward the end
1.402 + (void)Mem::Copy(iBase, data, len); //of the buffer. Stick the new data to the old data
1.403 + iLength += (iFilePos - aFilePos);
1.404 + iFilePos = aFilePos; //The new file pos is associated with the buffer
1.405 + iFileSize = Max(iFileSize, (iFilePos + iLength));
1.406 + len = 0; //No more new data
1.407 + iDirty = ETrue;
1.408 + }
1.409 + else
1.410 + //The "aFilePos" is too far before the "iFilePos". Write the buffer and associate the new pos with the buffer
1.411 + {
1.412 + err = DoFileWrite2(aFilePos);
1.413 + }
1.414 + }
1.415 + //2. The new write pos is after the associated file pos + the data length.
1.416 + else if(aFilePos > (iFilePos + iLength))
1.417 + {
1.418 + if(aFilePos > iFileSize) //Beyond the end of the file
1.419 + {
1.420 + if((iFilePos + iLength) == iFileSize && (aFilePos - iFilePos) < iCapacity)
1.421 + { //but within the buffer => extend the file with zeros.
1.422 + Mem::FillZ(iBase + iLength, aFilePos - iFilePos - iLength);
1.423 + iLength = aFilePos - iFilePos;
1.424 + iFileSize = Max(iFileSize, (iFilePos + iLength));
1.425 + iDirty = ETrue;
1.426 + }
1.427 + else
1.428 + //Beyond the end of the file and not in the buffer - set file size.
1.429 + {
1.430 + err = DoSetFileSize(aFilePos);
1.431 + }
1.432 + }
1.433 + else
1.434 + //Within the file, not in the buffer - write the buffer and associate the new file pos with the buffer
1.435 + {
1.436 + err = DoFileWrite2(aFilePos);
1.437 + }
1.438 + }
1.439 + //3. The new write pos is in the buffer, but the data length is too big
1.440 + // (For SQLite is OK, otherwise the whole block must be written to the file)
1.441 + //4. The new write pos is in the buffer, the data entirely fits in the buffer
1.442 + else
1.443 + {
1.444 + if(iCapacity == iLength) //The buffer is full. Write the buffer and associate the new file pos
1.445 + {
1.446 + err = DoFileWrite2(aFilePos);
1.447 + }
1.448 + if(err == KErrNone)
1.449 + {
1.450 + TInt amount = Min(len, (iCapacity - (aFilePos - iFilePos)));
1.451 + const TUint8* end = Mem::Copy(iBase + (aFilePos - iFilePos), data, amount);
1.452 + iLength = Max(iLength, (end - iBase));
1.453 + iFileSize = Max(iFileSize, (iFilePos + iLength));
1.454 + len -= amount;
1.455 + data += amount;
1.456 + aFilePos += amount;
1.457 + iDirty = ETrue;
1.458 + }
1.459 + }
1.460 + }
1.461 + __FILEBUF64_INVARIANT();
1.462 + return err;
1.463 + }
1.464 +
1.465 +/**
1.466 +Gets the current file size.
1.467 +
1.468 +@param aFileSize On return, the size of the file in bytes.
1.469 +
1.470 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.471 +
1.472 +See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
1.473 +
1.474 +@see RFileBuf64::Invariant()
1.475 +*/
1.476 +TInt RFileBuf64::Size(TInt64& aFileSize)
1.477 + {
1.478 + __FILEBUF64_INVARIANT();
1.479 + TInt err = DoFileSize();
1.480 + if(err == KErrNone)
1.481 + {
1.482 + aFileSize = iFileSize;
1.483 + }
1.484 + __FILEBUF64_INVARIANT();
1.485 + return err;
1.486 + }
1.487 +
1.488 +/**
1.489 +Sets the file size.
1.490 +
1.491 +If the size of the file is reduced, data may be lost from the end of the file.
1.492 +
1.493 +Note:
1.494 +
1.495 +1. The current file position remains unchanged unless SetSize() reduces the size
1.496 + of the file in such a way that the current file position is now beyond
1.497 + the end of the file. In this case, the current file position is set to
1.498 + the end of file.
1.499 +
1.500 +2. If the file was not opened for writing, an error is returned.
1.501 +
1.502 +@param aFileSize The new size of the file, in bytes. This value must not be negative, otherwise the function raises a panic.
1.503 +
1.504 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.505 +
1.506 +@panic Sqlite3 5 In _DEBUG mode - negative aFileSize value.
1.507 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.508 +
1.509 +@see RFileBuf64::Invariant()
1.510 +*/
1.511 +TInt RFileBuf64::SetSize(TInt64 aFileSize)
1.512 + {
1.513 + __ASSERT_DEBUG(aFileSize >= 0, __SQLITEPANIC(EFBufPanicFileSize));
1.514 + __FILEBUF64_INVARIANT();
1.515 + return DoSetFileSize(aFileSize);
1.516 + }
1.517 +
1.518 +/**
1.519 +Locks a region within the file as defined by a range of bytes.
1.520 +
1.521 +@see RFile64::Lock()
1.522 +
1.523 +@param aFilePos Position in file from which to lock; this is the offset from the beginning of the file.
1.524 +@param aLength Number of bytes to lock.
1.525 +
1.526 +@return KErrNone if successful, otherwise one of the other system-wide error
1.527 + codes.
1.528 +*/
1.529 +TInt RFileBuf64::Lock(TInt64 aFilePos, TInt64 aLength) const
1.530 + {
1.531 + __FILEBUF64_INVARIANT();
1.532 + TInt err = iFile.Lock(aFilePos, aLength);
1.533 + 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));
1.534 + return err;
1.535 + }
1.536 +
1.537 +/**
1.538 +Unlocks a region within the file as defined by a range of bytes.
1.539 +
1.540 +@see RFile64::UnLock()
1.541 +
1.542 +@param aFilePos Position in file from which to unlock; this is the offset from the beginning of the file.
1.543 +@param aLength Number of bytes to unlock.
1.544 +
1.545 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.546 +*/
1.547 +TInt RFileBuf64::UnLock(TInt64 aFilePos, TInt64 aLength) const
1.548 + {
1.549 + __FILEBUF64_INVARIANT();
1.550 + TInt err = iFile.UnLock(aFilePos, aLength);
1.551 + 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));
1.552 + return err;
1.553 + }
1.554 +
1.555 +/**
1.556 +Writes the pending data and then flushes the file.
1.557 +
1.558 +Although RFileBuf64::Close() also flushes internal buffers, it is better
1.559 +to call RFileBuf64::Flush() before the file is closed. This is because Close() returns no
1.560 +error information, so there is no way of telling whether the final data was
1.561 +written to the file successfully or not.
1.562 +
1.563 +@param aFlush The caller should call this function with aResetCachedFileSize parameter set,
1.564 + when the buffer file is shared between threads.
1.565 +
1.566 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.567 +
1.568 +See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
1.569 +
1.570 +@see RFileBuf64::Invariant()
1.571 +*/
1.572 +TInt RFileBuf64::Flush(TBool aResetCachedFileSize /*= EFalse*/)
1.573 + {
1.574 + __FILEBUF64_INVARIANT();
1.575 + TInt err = DoFileFlush();
1.576 + if(aResetCachedFileSize && err == KErrNone)
1.577 + {//Unset the iFileSize to force the file buffers used by the other threads to re-read the file size.
1.578 + iFileSize = KFileSizeNotSet;
1.579 + }
1.580 + return err;
1.581 + }
1.582 +
1.583 +/**
1.584 +Gets information about the drive on which this file resides.
1.585 +
1.586 +@param aDriveNumber On return, the drive number.
1.587 +
1.588 +@param aDriveInfo On return, contains information describing the drive
1.589 + and the medium mounted on it. The value of TDriveInfo::iType
1.590 + shows whether the drive contains media.
1.591 +
1.592 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.593 +
1.594 +See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
1.595 +
1.596 +@see RFileBuf64::Invariant()
1.597 +*/
1.598 +TInt RFileBuf64::Drive(TInt& aDriveNumber, TDriveInfo& aDriveInfo) const
1.599 + {
1.600 + __FILEBUF64_INVARIANT();
1.601 + TInt err = iFile.Drive(aDriveNumber, aDriveInfo);
1.602 + 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));
1.603 + return err;
1.604 + }
1.605 +
1.606 +/**
1.607 +Initializes RFileBuf64 data members with their initial values.
1.608 +Allocates memory for the file buffer.
1.609 +
1.610 +@return KErrNone if successful,
1.611 + KErrNoMemory out of memory;
1.612 +*/
1.613 +TInt RFileBuf64::DoPreInit()
1.614 + {
1.615 + DoDiscard();
1.616 + iReadAheadSize = RFileBuf64::KDefaultReadAheadSize;
1.617 + iBase = static_cast <TUint8*> (User::Alloc(iCapacity));
1.618 + return iBase ? KErrNone : KErrNoMemory;
1.619 + }
1.620 +
1.621 +/**
1.622 +Performs post-initialization of the RFileBuf64 object.
1.623 +If aInitErr is not KErrNone, then the buffer memory will be released.
1.624 +
1.625 +@param aInitErr The result of the performed before the call RFileBuf64 initialization.
1.626 +*/
1.627 +void RFileBuf64::DoPostInit(TInt aInitErr)
1.628 + {
1.629 + if(aInitErr != KErrNone)
1.630 + {
1.631 + User::Free(iBase);
1.632 + iBase = 0;
1.633 + }
1.634 + }
1.635 +
1.636 +/**
1.637 +Discards the content of the RFileBuf64 object returning it to the state as if it has just been created.
1.638 +*/
1.639 +void RFileBuf64::DoDiscard()
1.640 + {
1.641 + iLength = 0;
1.642 + iFilePos = 0;
1.643 + iFileSize = KFileSizeNotSet;
1.644 + iDirty = EFalse;
1.645 + iNextReadFilePos = KNextReadFilePosNotSet;
1.646 + iNextReadFilePosHits = 0;
1.647 + }
1.648 +
1.649 +/**
1.650 +Gets the current file size.
1.651 +If iFileSize value is valid, then no call to the file server will be made.
1.652 +Otherwise the file server will be called and the file size - stored (cached) in iFileSize data member for later use.
1.653 +
1.654 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.655 +
1.656 +See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
1.657 +
1.658 +@see RFileBuf64::Invariant()
1.659 +*/
1.660 +TInt RFileBuf64::DoFileSize()
1.661 + {
1.662 + __FILEBUF64_INVARIANT();
1.663 + if(iFileSize != KFileSizeNotSet)
1.664 + {
1.665 + __FILEBUF64_INVARIANT();
1.666 + return KErrNone;
1.667 + }
1.668 + TInt err = iFile.Size(iFileSize);
1.669 + SQLITE_TRACE_FBUF(OstTraceExt3(TRACE_INTERNALS, RFILEBUF64_DOFILESIZE, "FBuf;0x%X;RFileBuf64::DoFileSize;iFileSize=%lld;err=%d", (TUint)this, iFileSize, err));
1.670 + if(err != KErrNone)
1.671 + {
1.672 + DoDiscard();
1.673 + }
1.674 + __FILEBUF64_INVARIANT();
1.675 + return err;
1.676 + }
1.677 +
1.678 +/**
1.679 +Sets the file size.
1.680 +If the buffer contains pending data, the data will be written to the file
1.681 +before the "set file size" operation, if certain conditions are met.
1.682 +
1.683 +@param aFileSize The new size of the file, in bytes. This value must not be negative, otherwise the function raises a panic.
1.684 +
1.685 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.686 +
1.687 +@panic Sqlite3 5 In _DEBUG mode - negative aFileSize value.
1.688 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.689 +
1.690 +@see RFileBuf64::Invariant()
1.691 +*/
1.692 +TInt RFileBuf64::DoSetFileSize(TInt64 aFileSize)
1.693 + {
1.694 + __ASSERT_DEBUG(aFileSize >= 0, __SQLITEPANIC(EFBufPanicFileSize));
1.695 + __FILEBUF64_INVARIANT();
1.696 + if(aFileSize < iFilePos)
1.697 + {
1.698 + iDirty = EFalse;
1.699 + iLength = 0;
1.700 + }
1.701 + //If the new file size is "in" the buffer then change the "iLength"
1.702 + else if(aFileSize < (iFilePos + iLength))
1.703 + {
1.704 + iLength = aFileSize - iFilePos;
1.705 + }
1.706 + TInt err = iFile.SetSize(aFileSize);
1.707 + SQLITE_TRACE_FBUF(OstTraceExt4(TRACE_INTERNALS, RFILEBUF64_DOSETFILESIZE, "FBuf;0x%X;RFileBuf64::DoSetFileSize;iFileSize=%lld;aFileSize=%lld;err=%d", (TUint)this, iFileSize, aFileSize, err));
1.708 + if(err != KErrNone)
1.709 + {
1.710 + DoDiscard();
1.711 + }
1.712 + else
1.713 + {
1.714 + iFileSize = aFileSize;
1.715 + }
1.716 + __FILEBUF64_INVARIANT();
1.717 + return err;
1.718 + }
1.719 +
1.720 +/**
1.721 +Writes the pending data and flushes the file.
1.722 +
1.723 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.724 +
1.725 +See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
1.726 +
1.727 +@see RFileBuf64::Invariant()
1.728 +*/
1.729 +TInt RFileBuf64::DoFileFlush()
1.730 + {
1.731 + __FILEBUF64_INVARIANT();
1.732 + TInt err = DoFileWrite2();//Write the buffer if the iDirty flag is set. Do not preserve the buffer content and file pos.
1.733 + if(err != KErrNone)
1.734 + {
1.735 + __FILEBUF64_INVARIANT();
1.736 + return err;
1.737 + }
1.738 + err = iFile.Flush();
1.739 + SQLITE_TRACE_FBUF(OstTraceExt3(TRACE_INTERNALS, RFILEBUF64_DOFILEFLUSH, "FBuf;0x%X;RFileBuf64::DoFileFlush;iFileSize=%lld;err=%d", (TUint)this, iFileSize, err));
1.740 + if(err != KErrNone)
1.741 + {
1.742 + DoDiscard();
1.743 + }
1.744 + iLength = 0;
1.745 + __FILEBUF64_INVARIANT();
1.746 + return err;
1.747 + }
1.748 +
1.749 +/**
1.750 +Writes the buffered data to the file if the iLength value is > 0.
1.751 +If the file write operation extends the file, the iFileSize data member will be initialized with the new file size.
1.752 +No changes occur in the other data member values.
1.753 +
1.754 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.755 +
1.756 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.757 +
1.758 +@see RFileBuf64::DoFileWrite1()
1.759 +@see RFileBuf64::DoFileWrite2()
1.760 +@see RFileBuf64::Invariant()
1.761 +*/
1.762 +TInt RFileBuf64::DoFileWrite()
1.763 + {
1.764 + __FILEBUF64_INVARIANT();
1.765 + if(iLength == 0)
1.766 + {
1.767 + __FILEBUF64_INVARIANT();
1.768 + return KErrNone;
1.769 + }
1.770 + TPtrC8 data(iBase, iLength);
1.771 + TInt err = iFile.Write(iFilePos, data);
1.772 + 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));
1.773 + if(err == KErrNone)
1.774 + {
1.775 + iFileSize = Max(iFileSize, (iFilePos + iLength));
1.776 + }
1.777 + else
1.778 + {
1.779 + DoDiscard();
1.780 + }
1.781 + __FILEBUF64_INVARIANT();
1.782 + return err;
1.783 + }
1.784 +
1.785 +/**
1.786 +Writes the buffered data to the file if the iDirty flag is set.
1.787 +If the iDirty flag is set and the file write operation was successful, the iFilePos will be initialized with
1.788 +the aNewFilePos value, the iLength will be set to 0.
1.789 +This method is called from RFileBuf64::Read(), where:
1.790 + - if the buffer contains cached writes (iDirty flag is set), the buffer has to be flushed and iFilePos initialized
1.791 + with aNewFilePos - the offset in the file where the next file read operation should start from;
1.792 + - if the buffer contains cached reads, then nothing happens, the buffer content will be kept;
1.793 +The function resets the iDirty flag.
1.794 +
1.795 +@param aNewFilePos If the buffer is successfully written to the file the iFilePos data member will be initialized with
1.796 + the aNewFilePos value.
1.797 +
1.798 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.799 +
1.800 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.801 +
1.802 +@panic Sqlite3 4 In _DEBUG mode - negative aNewFilePos value.
1.803 +
1.804 +@see RFileBuf64::Read()
1.805 +@see RFileBuf64::DoFileWrite()
1.806 +@see RFileBuf64::DoFileWrite2()
1.807 +@see RFileBuf64::Invariant()
1.808 +*/
1.809 +TInt RFileBuf64::DoFileWrite1(TInt64 aNewFilePos)
1.810 + {
1.811 + __ASSERT_DEBUG(aNewFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos));
1.812 + __FILEBUF64_INVARIANT();
1.813 + TInt err = KErrNone;
1.814 + if(iDirty)
1.815 + {
1.816 + err = DoFileWrite();
1.817 + if(err == KErrNone)
1.818 + {
1.819 + iFilePos = aNewFilePos;
1.820 + iLength = 0;
1.821 + }
1.822 + }
1.823 + iDirty = EFalse;
1.824 + __FILEBUF64_INVARIANT();
1.825 + return err;
1.826 + }
1.827 +
1.828 +/*
1.829 +Writes the buffered data to the file if the iDirty flag is set.
1.830 +If the file write operation was successful or if the iDirty flag was not set, the iFilePos will be initialized with
1.831 +the aNewFilePos value, the iLength will be set to 0.
1.832 +This method is called from RFileBuf64::Write() an other RFileBuf64 methods (but not from RFileBuf64::Read()), where:
1.833 + - if the buffer contains cached writes (iDirty flag is set), the buffer has to be flushed and iFilePos initialized
1.834 + with aNewFilePos - the offset in the file for which the write data will be cached in the buffer;
1.835 + - if the buffer contains cached reads, then the buffer content will be destroyed, iFilePos initialized with aNewFilePos
1.836 + and iLength set to 0;
1.837 +The function resets the iDirty flag.
1.838 +The difference between RFileBuf64::DoFileWrite1() and RFileBuf64::DoFileWrite2() is:
1.839 + - RFileBuf64::DoFileWrite1() perserves the buffer content if iDirty is not set;
1.840 + - RFileBuf64::DoFileWrite2() always destroys the buffer content and initializes iFilePos;
1.841 +
1.842 +@param aNewFilePos If the buffer is successfully written to the file the iFilePos data member will be initialized with
1.843 + the aNewFilePos value.
1.844 +
1.845 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.846 +
1.847 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.848 +
1.849 +@panic Sqlite3 4 In _DEBUG mode - negative aNewFilePos value.
1.850 +
1.851 +@see RFileBuf64::Write()
1.852 +@see RFileBuf64::DoFileWrite()
1.853 +@see RFileBuf64::DoFileWrite1()
1.854 +@see RFileBuf64::Invariant()
1.855 +*/
1.856 +TInt RFileBuf64::DoFileWrite2(TInt64 aNewFilePos)
1.857 + {
1.858 + __ASSERT_DEBUG(aNewFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos));
1.859 + __FILEBUF64_INVARIANT();
1.860 + TInt err = KErrNone;
1.861 + if(iDirty)
1.862 + {
1.863 + err = DoFileWrite();
1.864 + }
1.865 + if(err == KErrNone)
1.866 + {
1.867 + iFilePos = aNewFilePos;
1.868 + iLength = 0;
1.869 + }
1.870 + iDirty = EFalse;
1.871 + __FILEBUF64_INVARIANT();
1.872 + return err;
1.873 + }
1.874 +
1.875 +/**
1.876 +This function discards the buffer content if the buffer contains cached read data.
1.877 +The function is called from RFileBuf64::Write(), because if the buffer contains cached read data,
1.878 +they cannot be mixed with the cached write data.
1.879 +Reason: for example the buffer contains 8Kb cached read data from file offset 0.
1.880 + The data write request is 10 bytes at offset 4000. The write data will be cached,
1.881 + because the buffer contains data from from this file area: [0..8192].
1.882 + The iDirty flag will be set. Later when RFileBuf64::Flush() is called, the whole
1.883 + 8Kb buffer will be written. There is nothing wrong with that, the file content will be consistent.
1.884 + But from performance point of view: 8Kb written vs. 10 bytes written - that may badly impact the performance.
1.885 +
1.886 +@see RFileBuf64::Write()
1.887 +
1.888 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.889 +*/
1.890 +void RFileBuf64::DoDiscardBufferedReadData()
1.891 + {
1.892 + __FILEBUF64_INVARIANT();
1.893 + if(!iDirty && iLength > 0)
1.894 + {
1.895 + iLength = 0;
1.896 + iFilePos = 0;
1.897 + iNextReadFilePos = KNextReadFilePosNotSet;
1.898 + iNextReadFilePosHits = 0;
1.899 + }
1.900 + __FILEBUF64_INVARIANT();
1.901 + }
1.902 +
1.903 +#ifdef _DEBUG
1.904 +
1.905 +/**
1.906 +RFileBuf64 invariant. Called in _DEBUG mode at the beginning and before the end of every RFileBuf64 method
1.907 +(except the init/destroy methods).
1.908 +
1.909 +@panic Sqlite3 11 In _DEBUG mode - null "this" pointer.
1.910 +@panic Sqlite3 1 In _DEBUG mode - negative iCapacity value.
1.911 +@panic Sqlite3 2 In _DEBUG mode - the buffer pointer is null (possible the buffer is not allocated or already destroyed).
1.912 +@panic Sqlite3 3 In _DEBUG mode - invalid iLength value (negative or bigger than iCapacity).
1.913 +@panic Sqlite3 4 In _DEBUG mode - negative iFilePos value.
1.914 +@panic Sqlite3 5 In _DEBUG mode - set but negative iFileSize value.
1.915 +@panic Sqlite3 6 In _DEBUG mode - null file handle (the RFile64 object is not created or already destroyed).
1.916 +@panic Sqlite3 13 In _DEBUG mode - set but negative iNextReadFilePos value.
1.917 +@panic Sqlite3 14 In _DEBUG mode - negative iNextReadFilePosHits value.
1.918 +@panic Sqlite3 15 In _DEBUG mode - iReadAheadSize is negative or is not power of two.
1.919 +*/
1.920 +void RFileBuf64::Invariant() const
1.921 + {
1.922 + __ASSERT_DEBUG(this != 0, __SQLITEPANIC(EFBufPanicNullThis));
1.923 + __ASSERT_DEBUG(iCapacity > 0, __SQLITEPANIC(EFBufPanicCapacity));
1.924 + __ASSERT_DEBUG(iBase != 0, __SQLITEPANIC(EFBufPanicNullBuf));
1.925 + __ASSERT_DEBUG(iLength >= 0 && iLength <= iCapacity, __SQLITEPANIC(EFBufPanicBufLen));
1.926 + __ASSERT_DEBUG(iFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos));
1.927 + __ASSERT_DEBUG(iFileSize == KFileSizeNotSet || iFileSize >= 0, __SQLITEPANIC(EFBufPanicFileSize));
1.928 + __ASSERT_DEBUG(iFile.SubSessionHandle() != 0, __SQLITEPANIC(EFBufPanicFileHandle));
1.929 + __ASSERT_DEBUG(iNextReadFilePos == KNextReadFilePosNotSet || iNextReadFilePos >= 0, __SQLITEPANIC(EFBufPanicNextReadFilePos));
1.930 + __ASSERT_DEBUG(iNextReadFilePosHits >= 0, __SQLITEPANIC(EFBufPanicNextReadFilePosHits));
1.931 + __ASSERT_DEBUG(iReadAheadSize > 0 && (iReadAheadSize & (iReadAheadSize - 1)) == 0, __SQLITEPANIC(EFBufPanicFileBlockSize));
1.932 + }
1.933 +
1.934 +#endif