os/persistentdata/persistentstorage/sqlite3api/OsLayer/FileBuf64.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 #include "FileBuf64.h"
    16 #include "OstTraceDefinitions.h"
    17 #ifdef OST_TRACE_COMPILER_IN_USE
    18 #include "FileBuf64Traces.h"
    19 #endif
    20 #include "SqliteTraceDef.h"
    21 
    22 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    23 
    24 /**
    25 This constant is used for initializing the RFileBuf64::iFileSize data member and means that
    26 the iFileSize is not yet initialized with the real file size value. 
    27 (RFileBuf64::iFileSize caches the file size value)
    28 @internalComponent
    29 */
    30 static const TInt KFileSizeNotSet = -1;
    31 
    32 /**
    33 This constant is used as a default initializer for the RFileBuf64::iNextReadFilePos data member,
    34 indicating that the "guessed" file read offset is invalid and should not be used.
    35 @internalComponent
    36 */
    37 static const TInt KNextReadFilePosNotSet = -1;
    38 
    39 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    40 ///////////////////////////        FBUF INVARIANT      ///////////////////////////////////////////////////////////////
    41 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    42 
    43 #ifdef _DEBUG
    44 
    45 #define __FILEBUF64_INVARIANT() Invariant()
    46 
    47 #else //_DEBUG
    48 
    49 #define __FILEBUF64_INVARIANT() void(0)
    50 
    51 #endif//_DEBUG
    52 
    53 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    54 ///////////////////////////        RFileBuf64    /////////////////////////////////////////////////////////////////////
    55 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    56 	
    57 /**
    58 Initializes RFileBuf64 data members with their default values.
    59 
    60 @param aSize Max file buffer size (capacity) in bytes.
    61 
    62 @panic Sqlite3 1 In _DEBUG mode - aSize is 0 or negative.
    63 */
    64 RFileBuf64::RFileBuf64(TInt aSize) :
    65 	iCapacity(aSize),
    66 	iBase(NULL),
    67 	iReadAheadSize(RFileBuf64::KDefaultReadAheadSize)
    68 	{
    69 	SQLITE_TRACE_FBUF(OstTraceExt3(TRACE_INTERNALS, RFILEBUF64_RFILEBUF64, "FBuf;0x%X;RFileBuf64::RFileBuf64;aSize=%d;iReadAheadSize=%d", (TUint)this, aSize, iReadAheadSize));
    70 	__ASSERT_DEBUG(aSize > 0, __SQLITEPANIC(EFBufPanicCapacity));
    71 	}
    72 
    73 /**
    74 Initializes the RFileBuf64 object and creates and opens a new file that will be accessed through RFileBuf64 public interface.
    75 If the file already exists, an error is returned.
    76 If the resulting path does not exist, then the operation cannot proceed and the function returns an error code.
    77 
    78 @param aFs       The file server session.
    79 @param aFileName The name of the file. Any path components (i.e. drive letter
    80                  or directory), which are not specified, are taken from
    81                  the session path.
    82 @param aFileMode The mode in which the file is opened. See TFileMode for details.
    83 
    84 @return KErrNone if successful, otherwise one of the other system-wide error codes.
    85 
    86 @see TFileMode
    87 @see RFile64::Create()
    88 
    89 @panic Sqlite3  7 In _DEBUG mode - Invalid aFs object (null file session handle).
    90 @panic Sqlite3 10 In _DEBUG mode - Invalid file name length (zero file name length).
    91 */
    92 TInt RFileBuf64::Create(RFs& aFs, const TDesC& aFileName, TUint aFileMode)
    93 	{
    94 	__ASSERT_DEBUG(aFs.Handle() != 0, __SQLITEPANIC(EFBufPanicFsHandle));
    95 	__ASSERT_DEBUG(aFileName.Length() > 0, __SQLITEPANIC(EFBufPanicFileNameLen));
    96 	
    97 	TInt err = DoPreInit();
    98 	if(err == KErrNone)
    99 	    {
   100 	    err = iFile.Create(aFs, aFileName, aFileMode);
   101 	    }
   102 	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));
   103 	DoPostInit(err);
   104 	return err;
   105 	}
   106 
   107 /**
   108 Initializes the RFileBuf64 object and opens an existing file that will be accessed through RFileBuf64 public interface.
   109 If the file does not already exist, an error is returned.
   110 
   111 @param aFs       The file server session.
   112 @param aFileName The name of the file. Any path components (i.e. drive letter
   113                  or directory), which are not specified, are taken from
   114                  the session path.
   115 @param aFileMode The mode in which the file is opened. See TFileMode for details.
   116 
   117 @return KErrNone if successful, otherwise one of the other system-wide error codes.
   118 
   119 @see TFileMode
   120 @see RFile64::Open()
   121 
   122 @panic Sqlite3  7 In _DEBUG mode - Invalid aFs object (null file session handle).
   123 @panic Sqlite3 10 In _DEBUG mode - Invalid file name length (zero file name length).
   124 */
   125 TInt RFileBuf64::Open(RFs& aFs, const TDesC& aFileName, TUint aFileMode)
   126 	{
   127 	__ASSERT_DEBUG(aFs.Handle() != 0, __SQLITEPANIC(EFBufPanicFsHandle));
   128 	__ASSERT_DEBUG(aFileName.Length() > 0, __SQLITEPANIC(EFBufPanicFileNameLen));
   129 	
   130     TInt err = DoPreInit();
   131     if(err == KErrNone)
   132         {
   133         err = iFile.Open(aFs, aFileName, aFileMode);
   134         }
   135 	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));
   136     DoPostInit(err);
   137 	return err;
   138 	}
   139 
   140 /**
   141 Initializes the RFileBuf64 object and creates and opens a temporary file with unique name that will be accessed through 
   142 RFileBuf64 public interface.
   143 
   144 @param aFs       The file server session.
   145 @param aPath     The directory in which the file is created.
   146 @param aFileName On return, contains the full path and file name of the file.
   147                  The filename is guaranteed to be unique within the directory
   148                  specified by aPath.
   149 @param aFileMode The mode in which the file is opened. The access mode is
   150                  automatically set to EFileWrite. See TFileMode for details.
   151 
   152 @return KErrNone if successful, otherwise one of the other system-wide error codes.
   153 
   154 @see TFileMode
   155 @see RFile64::Temp()
   156 
   157 @panic Sqlite3  7 In _DEBUG mode - Invalid aFs object (null file session handle).
   158 */
   159 TInt RFileBuf64::Temp(RFs& aFs, const TDesC& aPath, TFileName& aFileName, TUint aFileMode)
   160 	{
   161 	__ASSERT_DEBUG(aFs.Handle() != 0, __SQLITEPANIC(EFBufPanicFsHandle));
   162 	
   163     TInt err = DoPreInit();
   164     if(err == KErrNone)
   165         {
   166         err = iFile.Temp(aFs, aPath, aFileName, aFileMode);
   167         }
   168 	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));
   169     DoPostInit(err);
   170 	return err;
   171 	}
   172 
   173 /**
   174 Writes to the file the pending data (if the buffer contains pending data), closes the file and releases
   175 the RFileBuf64 resources. 
   176 RFileBuf64::Flush() should be called before RFileBuf64::Close() to ensure that if there are pending data, they will
   177 be written to the file and if the operation fails, the caller will be notified with an appropriate return error.
   178 
   179 @see RFileBuf64::Flush()
   180 */
   181 void RFileBuf64::Close()
   182 	{
   183 	SQLITE_TRACE_FBUF(OstTraceExt2(TRACE_INTERNALS, RFILEBUF64_CLOSE, "FBuf;0x%X;RFileBuf64::Close;iFile.SubSessionHandle()=0x%X", (TUint)this, (TUint)iFile.SubSessionHandle()));
   184 	if(iFile.SubSessionHandle() != 0 && iBase != 0)
   185 		{
   186 		(void)DoFileWrite2();
   187 		}
   188 	iFile.Close();
   189 	User::Free(iBase);
   190 	iBase = 0;
   191 	}
   192 
   193 /**
   194 Calculates and sets optimal read-ahead buffer size.
   195 aBlockSize and aReadRecBufSize values are retrieved by the caller from the file system.
   196 
   197 Initialization rules:
   198 Rule 1: If aReadRecBufSize is positive, bigger than the default read-ahead and 
   199         a power of two then the read-ahead value will be
   200         initialized with aReadRecBufSize (if aReadRecBufSize is less than the buffer capacity otherwise
   201         the buffer capacity will be used as a read-ahead value). 
   202 Rule 2: If rule#1 is not applicable then the same checks, as in rule#1, are performed this time for aBlockSize.
   203         If aBlockSize passes the checks then it will be used as a read-ahead value. 
   204 
   205 @param aBlockSize The size of a file block in bytes
   206 @param aReadRecBufSize The recommended buffer size for optimised reading performance
   207 
   208 @return The new read-ahead value
   209 
   210 @see TVolumeIOParamInfo
   211 */
   212 TInt RFileBuf64::SetReadAheadSize(TInt aBlockSize, TInt aReadRecBufSize)
   213 	{
   214 	__FILEBUF64_INVARIANT();
   215 	if((aReadRecBufSize & (aReadRecBufSize - 1)) == 0 && aReadRecBufSize > RFileBuf64::KDefaultReadAheadSize)
   216 		{
   217 		iReadAheadSize = aReadRecBufSize > iCapacity ? iCapacity : aReadRecBufSize;
   218 		}
   219 	else if((aBlockSize & (aBlockSize - 1)) == 0 && aBlockSize > RFileBuf64::KDefaultReadAheadSize)
   220 		{
   221 		iReadAheadSize = aBlockSize > iCapacity ? iCapacity : aBlockSize;
   222 		}
   223 	SQLITE_TRACE_FBUF(OstTraceExt4(TRACE_INTERNALS, RFILEBUF64_SETREADAHEADSIZE, "FBuf;0x%X;RFileBuf64::SetReadAheadSize;aBlockSize=%d;aReadRecBufSize=%d;iReadAheadSize=%d", (TUint)this, aBlockSize, aReadRecBufSize, iReadAheadSize));
   224 	__FILEBUF64_INVARIANT();
   225 	return iReadAheadSize;
   226 	}
   227 
   228 /**
   229 Reads from the file at the specified position (aFilePos).
   230 If the data to be read is in the buffer, then the data will be taken from the buffer.
   231 
   232 @param aFilePos Position of first byte to be read.  This is an offset from
   233             the start of the file. 
   234             If aPos is beyond the end of the file, the function returns
   235             a zero length descriptor.
   236 @param aDes Descriptor into which binary data is read. Any existing contents 
   237             are overwritten. On return, its length is set to the number of
   238             bytes read.
   239             
   240 @return KErrNone if successful, otherwise one of the other system-wide error  codes.
   241 
   242 @panic Sqlite3  4 In _DEBUG mode - negative aFilePos value.
   243 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
   244 
   245 @see RFileBuf64::Invariant()
   246 */
   247 TInt RFileBuf64::Read(TInt64 aFilePos, TDes8& aDes)
   248 	{
   249 	__ASSERT_DEBUG(aFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos));
   250 	__FILEBUF64_INVARIANT();
   251 	aDes.SetLength(0);
   252 	//1. The output buffer max len is 0
   253 	if(aDes.MaxLength() == 0)
   254 		{
   255 		__FILEBUF64_INVARIANT();
   256 		return KErrNone;	
   257 		}
   258 	//2. Initialize the "iFileSize" if it is not initialized yet
   259 	TInt err = DoFileSize();
   260 	if(err != KErrNone)
   261 		{
   262 		__FILEBUF64_INVARIANT();
   263 		return err;	
   264 		}
   265 	//3. Too big "read" request - read directly from the file
   266 	TInt len = aDes.MaxLength();
   267 	if(len > iCapacity)
   268 		{
   269 		if((aFilePos + len) > iFilePos && aFilePos < (iFilePos + iLength))
   270 			{//Write the pending data if the iDirty flag is set, otherwise preserve the buffer content.
   271 			err = DoFileWrite1(aFilePos);
   272 			}
   273 		if(err == KErrNone)
   274 			{
   275 			err = iFile.Read(aFilePos, aDes);
   276 			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));
   277 			}
   278 		__FILEBUF64_INVARIANT();
   279 		return err;
   280 		}
   281 	//4. The requested data size is smaller than the buffer capacity
   282 	TUint8* outptr = const_cast <TUint8*> (aDes.Ptr());
   283 	while(len > 0 && err == KErrNone && aFilePos < iFileSize)
   284 		{
   285 		//1. If part or all of the data is in the buffer - copy the data to the target location
   286 		if(aFilePos >= iFilePos && aFilePos < (iFilePos + iLength))
   287 			{
   288 			TInt blocklen = Min(len, (iFilePos + iLength - aFilePos));
   289 			outptr = Mem::Copy(outptr, iBase + (aFilePos - iFilePos), blocklen);
   290 			len -= blocklen;
   291 			aFilePos += blocklen;
   292 			}
   293 		//2. Perform a read-ahead operation
   294 		else
   295 			{
   296 			//Write the pending data if the iDirty flag is set, otherwise preserve the buffer content.
   297 			err = DoFileWrite1(aFilePos);
   298 			if(err != KErrNone)
   299 				{
   300 				break;	
   301 				}
   302 			if(iNextReadFilePos != aFilePos)
   303 				{//Guessed read ahead was wrong. Direct "file read" operation
   304 				iNextReadFilePosHits = 0;
   305 				TPtr8 ptr2(outptr, len);
   306 				err = iFile.Read(aFilePos, ptr2);
   307 				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));
   308 				if(err == KErrNone)
   309 					{
   310 					iNextReadFilePos = aFilePos + len;
   311 					len -= ptr2.Length();
   312 					}
   313 				break;
   314 				}
   315 			//The guessed from the previous "file read" operation file pos is correct. Start reading-ahead.
   316 			const TInt KMaxReadFilePosHits = 8;//The max read-ahead buffer size can be up to 2^8 times the iReadAheadSize
   317 			if(iNextReadFilePosHits < KMaxReadFilePosHits)
   318 				{
   319 				++iNextReadFilePosHits;
   320 				}
   321 			TInt maxReadAhead = iReadAheadSize * (1 << iNextReadFilePosHits);
   322 			TInt align = (aFilePos + len + maxReadAhead) & (iReadAheadSize - 1);
   323 			TInt readahead = maxReadAhead - align;
   324 			if(readahead < 0)
   325 				{
   326 				// if read-ahead doesn't cross block boundary do it all
   327 				readahead = maxReadAhead;	
   328 				}
   329 			TPtr8 ptr(iBase, Min(iCapacity, (len + readahead)));
   330 			err = iFile.Read(aFilePos, ptr);
   331 			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));
   332 			if(err == KErrNone)
   333 				{
   334 				iFilePos = aFilePos;
   335 				iLength = ptr.Length();	
   336 				iNextReadFilePos = iFilePos + iLength;
   337 				if(iLength == 0)
   338 					{
   339 					break;	
   340 					}
   341 				}
   342 			else
   343 				{
   344 				DoDiscard();	
   345 				}
   346 			}
   347 		}
   348 	aDes.SetLength(aDes.MaxLength() - len);
   349 	__FILEBUF64_INVARIANT();
   350 	return err;
   351 	}
   352 	
   353 /**
   354 Writes to the file at the specified offset (aFilePos) within the file.
   355 If certain conditions are met, the data will be stored in the buffer - no call to the file server.
   356 
   357 @param aFilePos The offset from the start of the file at which the first byte is written. 
   358                 If a position beyond the end of the file is specified, then
   359                 the write operation begins at the end of the file.
   360                 If the position has been locked, then the write fails.
   361             
   362 @param aData The descriptor from which binary data is written. The function writes 
   363              the entire contents of aData to the file.
   364 
   365 @return KErrNone if successful, otherwise one of the other system-wide error  codes.
   366 
   367 @panic Sqlite3  4 In _DEBUG mode - negative aFilePos value.
   368 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
   369 
   370 @see RFileBuf64::Invariant()
   371 */
   372 TInt RFileBuf64::Write(TInt64 aFilePos, const TDesC8& aData)
   373 	{
   374 	__ASSERT_DEBUG(aFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos));
   375 	__FILEBUF64_INVARIANT();
   376 	if(aData.Length() == 0)
   377 		{
   378 		__FILEBUF64_INVARIANT();
   379 		return KErrNone;	
   380 		}
   381 	TInt err = DoFileSize();
   382 	if(err != KErrNone)
   383 		{
   384 		__FILEBUF64_INVARIANT();
   385 		return err;	
   386 		}
   387 	DoDiscardBufferedReadData();
   388 	const TUint8* data = aData.Ptr();
   389 	for(TInt len = aData.Length(); len > 0 && err == KErrNone;)
   390 		{
   391 		//1. The new write pos is before the buffered file pos
   392 		if(aFilePos < iFilePos)
   393 			{
   394 			//If the new data sticks to/overlapps the old data and there is room in the buffer to move the old data 
   395 			//toward the end, then the new data can be copied at the beginning of the buffer.
   396 			if((aFilePos + len) >= iFilePos && (iFilePos - aFilePos) <= (iCapacity - iLength))
   397 				{
   398 				(void)Mem::Copy(iBase + (iFilePos - aFilePos), iBase, iLength);	//Make room - move the existing data toward the end
   399 				(void)Mem::Copy(iBase, data, len);								//of the buffer. Stick the new data to the old data
   400 				iLength += (iFilePos - aFilePos);
   401 				iFilePos = aFilePos;										//The new file pos is associated with the buffer
   402 				iFileSize = Max(iFileSize, (iFilePos + iLength));
   403 				len = 0;													//No more new data
   404 				iDirty = ETrue;	
   405 				}
   406 			else
   407 			//The "aFilePos" is too far before the "iFilePos". Write the buffer and associate the new pos with the buffer
   408 				{
   409 				err = DoFileWrite2(aFilePos);
   410 				}
   411 			}
   412 		//2. The new write pos is after the associated file pos + the data length.
   413 		else if(aFilePos > (iFilePos + iLength))
   414 			{
   415 			if(aFilePos > iFileSize)											//Beyond the end of the file
   416 				{
   417 				if((iFilePos + iLength) == iFileSize && (aFilePos - iFilePos) < iCapacity)	
   418 					{															//but within the buffer => extend the file with zeros.
   419 					Mem::FillZ(iBase + iLength, aFilePos - iFilePos - iLength);
   420 					iLength = aFilePos - iFilePos;
   421 					iFileSize = Max(iFileSize, (iFilePos + iLength));
   422 					iDirty = ETrue;	
   423 					}
   424 				else									
   425 				//Beyond the end of the file and not in the buffer - set file size.
   426 					{
   427 					err = DoSetFileSize(aFilePos);
   428 					}
   429 				}
   430 			else										
   431 			//Within the file, not in the buffer - write the buffer and associate the new file pos with the buffer
   432 				{
   433 				err = DoFileWrite2(aFilePos);
   434 				}
   435 			}
   436 		//3. The new write pos is in the buffer, but the data length is too big
   437 		//   (For SQLite is OK, otherwise the whole block must be written to the file)
   438 		//4. The new write pos is in the buffer, the data entirely fits in the buffer
   439 		else
   440 			{
   441 			if(iCapacity == iLength)			//The buffer is full. Write the buffer and associate the new file pos
   442 				{
   443 				err = DoFileWrite2(aFilePos);
   444 				}
   445 			if(err == KErrNone)
   446 				{
   447 				TInt amount = Min(len, (iCapacity - (aFilePos - iFilePos)));
   448 				const TUint8* end = Mem::Copy(iBase + (aFilePos - iFilePos), data, amount);
   449 				iLength = Max(iLength, (end - iBase));
   450 				iFileSize = Max(iFileSize, (iFilePos + iLength));
   451 				len -= amount;
   452 				data += amount;
   453 				aFilePos += amount;
   454 				iDirty = ETrue;	
   455 				}
   456 			}
   457 		}
   458 	__FILEBUF64_INVARIANT();
   459 	return err;
   460 	}
   461 	
   462 /**
   463 Gets the current file size.
   464 
   465 @param aFileSize On return, the size of the file in bytes.
   466 
   467 @return KErrNone if successful, otherwise one of the other system-wide error codes.
   468 
   469 See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
   470 
   471 @see RFileBuf64::Invariant()
   472 */
   473 TInt RFileBuf64::Size(TInt64& aFileSize)
   474 	{
   475 	__FILEBUF64_INVARIANT();
   476 	TInt err = DoFileSize();
   477 	if(err == KErrNone)
   478 		{
   479 		aFileSize = iFileSize;
   480 		}
   481 	__FILEBUF64_INVARIANT();
   482 	return err;
   483 	}
   484 
   485 /**
   486 Sets the file size.
   487 
   488 If the size of the file is reduced, data may be lost from the end of the file.
   489 
   490 Note:
   491 
   492 1. The current file position remains unchanged unless SetSize() reduces the size 
   493    of the file in such a way that the current file position is now beyond
   494    the end of the file. In this case, the current file position is set to
   495    the end of file. 
   496 
   497 2. If the file was not opened for writing, an error is returned.
   498 
   499 @param aFileSize The new size of the file, in bytes. This value must not be negative, otherwise the function raises a panic.
   500 
   501 @return KErrNone if successful, otherwise one of the other system-wide error codes.
   502 
   503 @panic Sqlite3  5 In _DEBUG mode - negative aFileSize value.
   504 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
   505 
   506 @see RFileBuf64::Invariant()
   507 */
   508 TInt RFileBuf64::SetSize(TInt64 aFileSize)
   509 	{
   510 	__ASSERT_DEBUG(aFileSize >= 0, __SQLITEPANIC(EFBufPanicFileSize));
   511 	__FILEBUF64_INVARIANT();
   512 	return DoSetFileSize(aFileSize);
   513 	}
   514 
   515 /**
   516 Locks a region within the file as defined by a range of bytes.
   517 
   518 @see RFile64::Lock()
   519 
   520 @param aFilePos Position in file from which to lock; this is the  offset from the beginning of the file.
   521 @param aLength  Number of bytes to lock.
   522 
   523 @return KErrNone if successful, otherwise one of the other  system-wide error 
   524         codes.
   525 */
   526 TInt RFileBuf64::Lock(TInt64 aFilePos, TInt64 aLength) const
   527 	{
   528 	__FILEBUF64_INVARIANT();
   529 	TInt err = iFile.Lock(aFilePos, aLength);
   530 	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));
   531 	return err;
   532 	}
   533 	
   534 /**
   535 Unlocks a region within the file as defined by a range of bytes.
   536 
   537 @see RFile64::UnLock()
   538 
   539 @param aFilePos Position in file from which to unlock; this is the  offset from the beginning of the file.
   540 @param aLength  Number of bytes to unlock.
   541 
   542 @return KErrNone if successful, otherwise one of the other  system-wide error codes.
   543 */
   544 TInt RFileBuf64::UnLock(TInt64 aFilePos, TInt64 aLength) const
   545 	{
   546 	__FILEBUF64_INVARIANT();
   547 	TInt err = iFile.UnLock(aFilePos, aLength);
   548 	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));
   549 	return err;
   550 	}
   551 
   552 /**
   553 Writes the pending data and then flushes the file.
   554 
   555 Although RFileBuf64::Close() also flushes internal buffers, it is better
   556 to call RFileBuf64::Flush() before the file is closed. This is because Close() returns no 
   557 error information, so there is no way of telling whether the final data was 
   558 written to the file successfully or not.
   559 
   560 @param aFlush The caller should call this function with aResetCachedFileSize parameter set, 
   561 			  when the buffer file is shared between threads.
   562 
   563 @return KErrNone if successful, otherwise one of the other system-wide error codes.
   564 
   565 See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
   566 
   567 @see RFileBuf64::Invariant()
   568 */
   569 TInt RFileBuf64::Flush(TBool aResetCachedFileSize /*= EFalse*/)
   570 	{
   571 	__FILEBUF64_INVARIANT();
   572 	TInt err = DoFileFlush();
   573 	if(aResetCachedFileSize && err == KErrNone)
   574 		{//Unset the iFileSize to force the file buffers used by the other threads to re-read the file size.
   575 		iFileSize = KFileSizeNotSet;
   576 		}
   577 	return err;
   578 	}
   579 
   580 /**
   581 Gets information about the drive on which this file resides.
   582  
   583 @param aDriveNumber On return, the drive number.
   584 
   585 @param aDriveInfo   On return, contains information describing the drive
   586                     and the medium mounted on it. The value of TDriveInfo::iType
   587                     shows whether the drive contains media.
   588 
   589 @return KErrNone if successful, otherwise one of the other system-wide error codes.
   590 
   591 See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
   592 
   593 @see RFileBuf64::Invariant()
   594 */
   595 TInt RFileBuf64::Drive(TInt& aDriveNumber, TDriveInfo& aDriveInfo) const
   596 	{
   597 	__FILEBUF64_INVARIANT();
   598 	TInt err = iFile.Drive(aDriveNumber, aDriveInfo);
   599 	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));
   600 	return err;
   601 	}
   602 
   603 /**
   604 Initializes RFileBuf64 data members with their initial values.   
   605 Allocates memory for the file buffer. 
   606  
   607 @return KErrNone if successful, 
   608         KErrNoMemory out of memory;
   609 */
   610 TInt RFileBuf64::DoPreInit()
   611     {
   612     DoDiscard();
   613     iReadAheadSize = RFileBuf64::KDefaultReadAheadSize;
   614     iBase = static_cast <TUint8*> (User::Alloc(iCapacity));
   615     return iBase ? KErrNone : KErrNoMemory; 
   616     }
   617 
   618 /**
   619 Performs post-initialization of the RFileBuf64 object.   
   620 If aInitErr is not KErrNone, then the buffer memory will be released.
   621 
   622 @param aInitErr The result of the performed before the call RFileBuf64 initialization.
   623 */
   624 void RFileBuf64::DoPostInit(TInt aInitErr)
   625     {
   626     if(aInitErr != KErrNone)
   627         {
   628         User::Free(iBase);
   629         iBase = 0;
   630         }
   631     }
   632 
   633 /**
   634 Discards the content of the RFileBuf64 object returning it to the state as if it has just been created. 
   635 */
   636 void RFileBuf64::DoDiscard()
   637 	{
   638 	iLength = 0;
   639 	iFilePos = 0;
   640 	iFileSize = KFileSizeNotSet;
   641 	iDirty = EFalse;
   642 	iNextReadFilePos = KNextReadFilePosNotSet;
   643 	iNextReadFilePosHits = 0;
   644 	}
   645 
   646 /**
   647 Gets the current file size. 
   648 If iFileSize value is valid, then no call to the file server will be made.
   649 Otherwise the file server will be called and the file size - stored (cached) in iFileSize data member for later use.
   650 
   651 @return KErrNone if successful, otherwise one of the other system-wide error codes.
   652 
   653 See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
   654 
   655 @see RFileBuf64::Invariant()
   656 */
   657 TInt RFileBuf64::DoFileSize()
   658 	{
   659 	__FILEBUF64_INVARIANT();
   660 	if(iFileSize != KFileSizeNotSet)
   661 		{
   662 		__FILEBUF64_INVARIANT();
   663 		return KErrNone;
   664 		}
   665 	TInt err = iFile.Size(iFileSize);
   666 	SQLITE_TRACE_FBUF(OstTraceExt3(TRACE_INTERNALS, RFILEBUF64_DOFILESIZE, "FBuf;0x%X;RFileBuf64::DoFileSize;iFileSize=%lld;err=%d", (TUint)this, iFileSize, err));
   667 	if(err != KErrNone)
   668 		{
   669 		DoDiscard();
   670 		}
   671 	__FILEBUF64_INVARIANT();
   672 	return err;
   673 	}
   674 
   675 /**
   676 Sets the file size.
   677 If the buffer contains pending data, the data will be written to the file 
   678 before the "set file size" operation, if certain conditions are met. 
   679 
   680 @param aFileSize The new size of the file, in bytes. This value must not be negative, otherwise the function raises a panic.
   681 
   682 @return KErrNone if successful, otherwise one of the other system-wide error codes.
   683 
   684 @panic Sqlite3  5 In _DEBUG mode - negative aFileSize value.
   685 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
   686 
   687 @see RFileBuf64::Invariant()
   688 */
   689 TInt RFileBuf64::DoSetFileSize(TInt64 aFileSize)
   690 	{
   691 	__ASSERT_DEBUG(aFileSize >= 0, __SQLITEPANIC(EFBufPanicFileSize));
   692 	__FILEBUF64_INVARIANT();
   693 	if(aFileSize < iFilePos)
   694 		{
   695 		iDirty = EFalse;
   696 		iLength = 0;	
   697 		}
   698 	//If the new file size is "in" the buffer then change the "iLength"
   699 	else if(aFileSize < (iFilePos + iLength))
   700 		{
   701 		iLength = aFileSize - iFilePos;
   702 		}
   703 	TInt err = iFile.SetSize(aFileSize);
   704 	SQLITE_TRACE_FBUF(OstTraceExt4(TRACE_INTERNALS, RFILEBUF64_DOSETFILESIZE, "FBuf;0x%X;RFileBuf64::DoSetFileSize;iFileSize=%lld;aFileSize=%lld;err=%d", (TUint)this, iFileSize, aFileSize, err));
   705 	if(err != KErrNone)
   706 		{
   707 		DoDiscard();
   708 		}
   709 	else
   710 		{
   711 		iFileSize = aFileSize;
   712 		}
   713 	__FILEBUF64_INVARIANT();
   714 	return err;
   715 	}
   716 
   717 /**
   718 Writes the pending data and flushes the file.
   719 
   720 @return KErrNone if successful, otherwise one of the other system-wide error codes.
   721 
   722 See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
   723 
   724 @see RFileBuf64::Invariant()
   725 */
   726 TInt RFileBuf64::DoFileFlush()
   727 	{
   728 	__FILEBUF64_INVARIANT();
   729 	TInt err = DoFileWrite2();//Write the buffer if the iDirty flag is set. Do not preserve the buffer content and file pos.
   730 	if(err != KErrNone)
   731 		{
   732 		__FILEBUF64_INVARIANT();
   733 		return err;	
   734 		}
   735 	err = iFile.Flush();
   736 	SQLITE_TRACE_FBUF(OstTraceExt3(TRACE_INTERNALS, RFILEBUF64_DOFILEFLUSH, "FBuf;0x%X;RFileBuf64::DoFileFlush;iFileSize=%lld;err=%d", (TUint)this, iFileSize, err));
   737 	if(err != KErrNone)
   738 		{
   739 		DoDiscard();
   740 		}
   741 	iLength = 0;
   742 	__FILEBUF64_INVARIANT();
   743 	return err;
   744 	}
   745 
   746 /**
   747 Writes the buffered data to the file if the iLength value is > 0.
   748 If the file write operation extends the file, the iFileSize data member will be initialized with the new file size.
   749 No changes occur in the other data member values.
   750 
   751 @return KErrNone if successful, otherwise one of the other system-wide error codes.
   752 
   753 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
   754 
   755 @see RFileBuf64::DoFileWrite1()
   756 @see RFileBuf64::DoFileWrite2()
   757 @see RFileBuf64::Invariant()
   758 */
   759 TInt RFileBuf64::DoFileWrite()
   760 	{
   761 	__FILEBUF64_INVARIANT();
   762 	if(iLength == 0)
   763 		{
   764 		__FILEBUF64_INVARIANT();
   765 		return KErrNone;	
   766 		}
   767 	TPtrC8 data(iBase, iLength);		
   768 	TInt err = iFile.Write(iFilePos, data);
   769 	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));
   770 	if(err == KErrNone)
   771 		{
   772 		iFileSize = Max(iFileSize, (iFilePos + iLength));
   773 		}
   774 	else
   775 		{
   776 		DoDiscard();
   777 		}
   778 	__FILEBUF64_INVARIANT();
   779 	return err;
   780 	}
   781 
   782 /**
   783 Writes the buffered data to the file if the iDirty flag is set.
   784 If the iDirty flag is set and the file write operation was successful, the iFilePos will be initialized with
   785 the aNewFilePos value, the iLength will be set to 0.
   786 This method is called from RFileBuf64::Read(), where:
   787  - if the buffer contains cached writes (iDirty flag is set), the buffer has to be flushed and iFilePos initialized
   788    with aNewFilePos - the offset in the file where the next file read operation should start from;
   789  - if the buffer contains cached reads, then nothing happens, the buffer content will be kept;
   790 The function resets the iDirty flag.
   791 
   792 @param aNewFilePos If the buffer is successfully written to the file the iFilePos data member will be initialized with
   793 				   the aNewFilePos value.
   794 
   795 @return KErrNone if successful, otherwise one of the other system-wide error codes.
   796 
   797 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
   798 				   
   799 @panic Sqlite3  4 In _DEBUG mode - negative aNewFilePos value.
   800 
   801 @see RFileBuf64::Read()
   802 @see RFileBuf64::DoFileWrite()
   803 @see RFileBuf64::DoFileWrite2()
   804 @see RFileBuf64::Invariant()
   805 */
   806 TInt RFileBuf64::DoFileWrite1(TInt64 aNewFilePos)
   807 	{
   808 	__ASSERT_DEBUG(aNewFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos));
   809 	__FILEBUF64_INVARIANT();
   810 	TInt err = KErrNone;
   811 	if(iDirty)
   812 		{
   813 		err = DoFileWrite();
   814 		if(err == KErrNone)	
   815 			{
   816 			iFilePos = aNewFilePos;
   817 			iLength = 0;
   818 			}
   819 		}
   820 	iDirty = EFalse;
   821 	__FILEBUF64_INVARIANT();
   822 	return err;		
   823 	}
   824 
   825 /*
   826 Writes the buffered data to the file if the iDirty flag is set.
   827 If the file write operation was successful or if the iDirty flag was not set, the iFilePos will be initialized with
   828 the aNewFilePos value, the iLength will be set to 0.
   829 This method is called from RFileBuf64::Write() an other RFileBuf64 methods (but not from RFileBuf64::Read()), where:
   830  - if the buffer contains cached writes (iDirty flag is set), the buffer has to be flushed and iFilePos initialized
   831    with aNewFilePos - the offset in the file for which the write data will be cached in the buffer;
   832  - if the buffer contains cached reads, then the buffer content will be destroyed, iFilePos initialized with aNewFilePos
   833    and iLength set to 0;
   834 The function resets the iDirty flag.
   835 The difference between RFileBuf64::DoFileWrite1() and RFileBuf64::DoFileWrite2() is:
   836  - RFileBuf64::DoFileWrite1() perserves the buffer content if iDirty is not set;
   837  - RFileBuf64::DoFileWrite2() always destroys the buffer content and initializes iFilePos;
   838 
   839 @param aNewFilePos If the buffer is successfully written to the file the iFilePos data member will be initialized with
   840 				   the aNewFilePos value.
   841 
   842 @return KErrNone if successful, otherwise one of the other system-wide error codes.
   843 
   844 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
   845 				   
   846 @panic Sqlite3  4 In _DEBUG mode - negative aNewFilePos value.
   847 
   848 @see RFileBuf64::Write()
   849 @see RFileBuf64::DoFileWrite()
   850 @see RFileBuf64::DoFileWrite1()
   851 @see RFileBuf64::Invariant()
   852 */
   853 TInt RFileBuf64::DoFileWrite2(TInt64 aNewFilePos)
   854 	{
   855 	__ASSERT_DEBUG(aNewFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos));
   856 	__FILEBUF64_INVARIANT();
   857 	TInt err = KErrNone;
   858 	if(iDirty)
   859 		{
   860 		err = DoFileWrite();
   861 		}
   862 	if(err == KErrNone)	
   863 		{
   864 		iFilePos = aNewFilePos;
   865 		iLength = 0;
   866 		}
   867 	iDirty = EFalse;
   868 	__FILEBUF64_INVARIANT();
   869 	return err;
   870 	}
   871 
   872 /**
   873 This function discards the buffer content if the buffer contains cached read data.
   874 The function is called from RFileBuf64::Write(), because if the buffer contains cached read data,
   875 they cannot be mixed with the cached write data.
   876 Reason: for example the buffer contains 8Kb cached read data from file offset 0.
   877         The data write request is 10 bytes at offset 4000. The write data will be cached,
   878         because the buffer contains data from from this file area: [0..8192].
   879         The iDirty flag will be set. Later when RFileBuf64::Flush() is called, the whole
   880         8Kb buffer will be written. There is nothing wrong with that, the file content will be consistent.
   881         But from performance point of view: 8Kb written vs. 10 bytes written - that may badly impact the performance.
   882 
   883 @see RFileBuf64::Write()
   884 
   885 See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
   886 */
   887 void RFileBuf64::DoDiscardBufferedReadData()
   888 	{
   889 	__FILEBUF64_INVARIANT();
   890 	if(!iDirty && iLength > 0)
   891 		{
   892 		iLength = 0;
   893 		iFilePos = 0;
   894 		iNextReadFilePos = KNextReadFilePosNotSet;
   895 		iNextReadFilePosHits = 0;
   896 		}
   897 	__FILEBUF64_INVARIANT();
   898 	}
   899 
   900 #ifdef _DEBUG
   901 
   902 /**
   903 RFileBuf64 invariant. Called in _DEBUG mode at the beginning and before the end of every RFileBuf64 method
   904 (except the init/destroy methods).
   905 
   906 @panic Sqlite3  11 In _DEBUG mode - null "this" pointer.
   907 @panic Sqlite3   1 In _DEBUG mode - negative iCapacity value.
   908 @panic Sqlite3   2 In _DEBUG mode - the buffer pointer is null (possible the buffer is not allocated or already destroyed).
   909 @panic Sqlite3   3 In _DEBUG mode - invalid iLength value (negative or bigger than iCapacity).
   910 @panic Sqlite3   4 In _DEBUG mode - negative iFilePos value.
   911 @panic Sqlite3   5 In _DEBUG mode - set but negative iFileSize value.
   912 @panic Sqlite3   6 In _DEBUG mode - null file handle (the RFile64 object is not created or already destroyed).
   913 @panic Sqlite3  13 In _DEBUG mode - set but negative iNextReadFilePos value.
   914 @panic Sqlite3  14 In _DEBUG mode - negative iNextReadFilePosHits value.
   915 @panic Sqlite3  15 In _DEBUG mode - iReadAheadSize is negative or is not power of two.
   916 */
   917 void RFileBuf64::Invariant() const
   918 	{
   919 	__ASSERT_DEBUG(this != 0, __SQLITEPANIC(EFBufPanicNullThis));
   920 	__ASSERT_DEBUG(iCapacity > 0, __SQLITEPANIC(EFBufPanicCapacity));
   921 	__ASSERT_DEBUG(iBase != 0, __SQLITEPANIC(EFBufPanicNullBuf));
   922 	__ASSERT_DEBUG(iLength >= 0 && iLength <= iCapacity, __SQLITEPANIC(EFBufPanicBufLen));
   923 	__ASSERT_DEBUG(iFilePos >= 0, __SQLITEPANIC(EFBufPanicFilePos));
   924 	__ASSERT_DEBUG(iFileSize == KFileSizeNotSet || iFileSize >= 0, __SQLITEPANIC(EFBufPanicFileSize));
   925 	__ASSERT_DEBUG(iFile.SubSessionHandle() != 0, __SQLITEPANIC(EFBufPanicFileHandle));
   926 	__ASSERT_DEBUG(iNextReadFilePos == KNextReadFilePosNotSet || iNextReadFilePos >= 0, __SQLITEPANIC(EFBufPanicNextReadFilePos));
   927 	__ASSERT_DEBUG(iNextReadFilePosHits >= 0, __SQLITEPANIC(EFBufPanicNextReadFilePosHits));
   928 	__ASSERT_DEBUG(iReadAheadSize > 0 && (iReadAheadSize & (iReadAheadSize - 1)) == 0, __SQLITEPANIC(EFBufPanicFileBlockSize));
   929 	}
   930 	
   931 #endif