1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/sql/OsLayer/FileBuf64.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1195 @@
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 +
1.20 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.21 +/////////////////////////// PROFILER ////////////////////////////////////////////////////////////////////
1.22 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.23 +
1.24 +#ifdef _SQLPROFILER
1.25 +
1.26 +extern TBool TheOsCallTimeDetailedProfileEnabled;//If true, the OS porting layer call details are enabled and for each call an entry will be added to the log file (epocwind.out).
1.27 +
1.28 +#define PROFILE_READ(pos, amount, err) \
1.29 + do \
1.30 + { \
1.31 + if(TheOsCallTimeDetailedProfileEnabled) \
1.32 + { \
1.33 + ++iFileReadCount; iFileReadAmount += (amount); \
1.34 + RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Read¬%d¬%ld¬%d¬%ld¬%d\r\n"), (TUint32)this, iFileReadCount, pos, amount, iFileReadAmount, err); \
1.35 + } \
1.36 + } while(0)
1.37 +
1.38 +#define PROFILE_WRITE(pos, amount, err) \
1.39 + do \
1.40 + { \
1.41 + if(TheOsCallTimeDetailedProfileEnabled) \
1.42 + { \
1.43 + ++iFileWriteCount; iFileWriteAmount += (amount); \
1.44 + RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Write¬%d¬%ld¬%d¬%ld¬%d\r\n"), (TUint32)this, iFileWriteCount, pos, amount, iFileWriteAmount, err); \
1.45 + } \
1.46 + } while(0)
1.47 +
1.48 +#define PROFILE_SIZE(size, err) \
1.49 + do \
1.50 + { \
1.51 + if(TheOsCallTimeDetailedProfileEnabled) \
1.52 + { \
1.53 + ++iFileSizeCount; \
1.54 + RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Size¬%d¬%ld¬¬¬%d\r\n"), (TUint32)this, iFileSizeCount, size, err); \
1.55 + } \
1.56 + } while(0)
1.57 +
1.58 +#define PROFILE_SETSIZE(size, err) \
1.59 + do \
1.60 + { \
1.61 + if(TheOsCallTimeDetailedProfileEnabled) \
1.62 + { \
1.63 + ++iFileSetSizeCount; \
1.64 + RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬SetSize¬%d¬%ld¬¬¬%d\r\n"), (TUint32)this, iFileSetSizeCount, size, err); \
1.65 + } \
1.66 + } while(0)
1.67 +
1.68 +#define PROFILE_FLUSH(err) \
1.69 + do \
1.70 + { \
1.71 + if(TheOsCallTimeDetailedProfileEnabled) \
1.72 + { \
1.73 + ++iFileFlushCount; \
1.74 + RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Flush¬%d¬¬¬¬%d\r\n"), (TUint32)this, iFileFlushCount, err); \
1.75 + } \
1.76 + } while(0)
1.77 +
1.78 +#define PROFILE_CREATE(fname, err) \
1.79 + do \
1.80 + { \
1.81 + if(TheOsCallTimeDetailedProfileEnabled) \
1.82 + { \
1.83 + RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Create¬¬¬¬¬%d¬%S\r\n"), (TUint32)this, err, &fname); \
1.84 + } \
1.85 + } while(0)
1.86 +
1.87 +#define PROFILE_OPEN(fname, err) \
1.88 + do \
1.89 + { \
1.90 + if(TheOsCallTimeDetailedProfileEnabled) \
1.91 + { \
1.92 + RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Open¬¬¬¬¬%d¬%S\r\n"), (TUint32)this, err, &fname); \
1.93 + } \
1.94 + } while(0)
1.95 +
1.96 +#define PROFILE_TEMP(fname, err) \
1.97 + do \
1.98 + { \
1.99 + if(TheOsCallTimeDetailedProfileEnabled) \
1.100 + { \
1.101 + RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Temp¬¬¬¬¬%d¬%S\r\n"), (TUint32)this, err, &fname); \
1.102 + } \
1.103 + } while(0)
1.104 +
1.105 +#define PROFILE_ADOPT(fname, err) \
1.106 + do \
1.107 + { \
1.108 + if(TheOsCallTimeDetailedProfileEnabled) \
1.109 + { \
1.110 + RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Adopt¬¬¬¬¬%d¬%S\r\n"), (TUint32)this, err, &fname); \
1.111 + } \
1.112 + } while(0)
1.113 +
1.114 +#define PROFILE_CLOSE() \
1.115 + do \
1.116 + { \
1.117 + if(TheOsCallTimeDetailedProfileEnabled) \
1.118 + { \
1.119 + RDebug::Print(_L("[SQL-FBUF]¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬\"%X\"¬Close¬¬¬¬¬¬\r\n"), (TUint32)this); \
1.120 + } \
1.121 + } while(0)
1.122 +
1.123 +//Resets the profiler counters
1.124 +void RFileBuf64::ProfilerReset()
1.125 + {
1.126 + iFileReadCount = 0; iFileReadAmount = 0; iFileWriteCount = 0; iFileWriteAmount = 0; iFileSizeCount = 0; iFileSetSizeCount = 0; iFileFlushCount = 0;
1.127 + }
1.128 +
1.129 +#else
1.130 +
1.131 +#define PROFILE_READ(pos,amount, err) void(0)
1.132 +#define PROFILE_WRITE(pos,amount, err) void(0)
1.133 +
1.134 +#define PROFILE_SIZE(size, err) void(0)
1.135 +#define PROFILE_SETSIZE(size, err) void(0)
1.136 +#define PROFILE_FLUSH(err) void(0)
1.137 +
1.138 +#define PROFILE_CREATE(fname, err) void(0)
1.139 +#define PROFILE_OPEN(fname, err) void(0)
1.140 +#define PROFILE_TEMP(fname, err) void(0)
1.141 +#define PROFILE_ADOPT(fname, err) void(0)
1.142 +#define PROFILE_CLOSE() void(0)
1.143 +
1.144 +#endif//_SQLPROFILER
1.145 +
1.146 +/**
1.147 +This constant is used for initializing the RFileBuf64::iFileSize data member and means that
1.148 +the iFileSize is not yet initialized with the real file size value.
1.149 +(RFileBuf64::iFileSize caches the file size value)
1.150 +@internalComponent
1.151 +*/
1.152 +static const TInt KFileSizeNotSet = -1;
1.153 +
1.154 +/**
1.155 +This constant is used as a default initializer for the RFileBuf64::iNextReadFilePos data member,
1.156 +indicating that the "guessed" file read offset is invalid and should not be used.
1.157 +@internalComponent
1.158 +*/
1.159 +static const TInt KNextReadFilePosNotSet = -1;
1.160 +
1.161 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.162 +/////////////////////////// ASSERTS & INVARIANT //////////////////////////////////////////////////////////
1.163 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.164 +
1.165 +#ifdef _DEBUG
1.166 +
1.167 +#define __FILEBUF64_INVARIANT() Invariant()
1.168 +
1.169 +/**
1.170 +String literal used in _DEBUG mode for indicating that the reported panic happened inside the RFileBuf64 implementation.
1.171 +
1.172 +@see TFileBufPanic64
1.173 +@internalComponent
1.174 +*/
1.175 +_LIT(KPanicCategory, "FBuf64");
1.176 +
1.177 +/**
1.178 +Set of numeric constants used together with the KPanicCategory string literal in _DEBUG mode for providing more detailed
1.179 +information about the reason of the panic.
1.180 +
1.181 +@see KPanicCategory
1.182 +@internalComponent
1.183 +*/
1.184 +enum TFileBufPanic64
1.185 + {
1.186 + EFBufPanicCapacity = 1, //1
1.187 + EFBufPanicNullBuf,
1.188 + EFBufPanicBufLen,
1.189 + EFBufPanicFilePos,
1.190 + EFBufPanicFileSize, //5
1.191 + EFBufPanicFileHandle,
1.192 + EFBufPanicFsHandle,
1.193 + EFBufPanicMsgHandle,
1.194 + EFBufPanicMsgIndex,
1.195 + EFBufPanicFileNameLen, //10
1.196 + EFBufPanicNullThis,
1.197 + EFBufPanicDirty,
1.198 + EFBufPanicNextReadFilePos,
1.199 + EFBufPanicNextReadFilePosHits,
1.200 + EFBufPanicFileBlockSize, //15
1.201 + EFBufPanicRwDataLength,
1.202 + };
1.203 +
1.204 +/**
1.205 +Helper function used in the implementation of the __FBUF64_ASSERT() macro.
1.206 +In case if the expression in __FBUF64_ASSERT() macro evaluates to false,
1.207 +PanicFileBuf64() will use the supplied aLine and aPanicCode arguments together with the KPanicCategory string literal
1.208 +to prepare and print out a line (including the time of the panic) to the default log. The calling thread will be panic'ed
1.209 +after that.
1.210 +
1.211 +@see TFileBufPanic64
1.212 +@see KPanicCategory
1.213 +@internalComponent
1.214 +*/
1.215 +static void PanicFileBuf64(TInt aLine, TFileBufPanic64 aPanicCode)
1.216 + {
1.217 + TTime time;
1.218 + time.HomeTime();
1.219 + TDateTime dt = time.DateTime();
1.220 + TBuf<16> tbuf;
1.221 + tbuf.Format(_L("%02d:%02d:%02d.%06d"), dt.Hour(), dt.Minute(), dt.Second(), dt.MicroSecond());
1.222 +
1.223 + TBuf<64> buf;
1.224 + _LIT(KFormat,"**%S:RFileBuf64 panic %d, at line(%d)");
1.225 + buf.Format(KFormat, &tbuf, aPanicCode, aLine);
1.226 + RDebug::Print(buf);
1.227 + User::Panic(KPanicCategory, aPanicCode);
1.228 + }
1.229 +
1.230 +/**
1.231 +This macro should be used when there is a need to panic the client/server if "expr" condition is not satisfied.
1.232 +Works in only in debug mode. In release mode evaluates to nothing.
1.233 +
1.234 +@see TFileBufPanic64
1.235 +@see KPanicCategory
1.236 +@see PanicFileBuf64()
1.237 +@internalComponent
1.238 +*/
1.239 +#define __FBUF64_ASSERT(expr, panicCode) (void)(!(expr) ? ::PanicFileBuf64(__LINE__, panicCode) : void(0))
1.240 +
1.241 +#else //_DEBUG
1.242 +
1.243 +#define __FILEBUF64_INVARIANT() void(0)
1.244 +
1.245 +#define __FBUF64_ASSERT(expr, panicCode) void(0)
1.246 +
1.247 +#endif//_DEBUG
1.248 +
1.249 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.250 +/////////////////////////// RFileBuf64 /////////////////////////////////////////////////////////////////////
1.251 +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1.252 +
1.253 +/**
1.254 +Initializes RFileBuf64 data members with their default values.
1.255 +
1.256 +@param aMinCapacity Minimal file buffer size (capacity) in bytes.
1.257 +
1.258 +@panic FBuf64 1 In _DEBUG mode - aMinCapacity is 0 or negative.
1.259 +*/
1.260 +RFileBuf64::RFileBuf64(TInt aMinCapacity) :
1.261 + iCapacity(aMinCapacity),
1.262 + iBase(NULL),
1.263 + iReadAheadSize(RFileBuf64::KDefaultReadAheadSize),
1.264 + iOptimized(EFalse)
1.265 + {
1.266 + __FBUF64_ASSERT(aMinCapacity > 0, EFBufPanicCapacity);
1.267 + }
1.268 +
1.269 +/**
1.270 +Initializes the RFileBuf64 object and creates and opens a new file that will be accessed through RFileBuf64 public interface.
1.271 +If the file already exists, an error is returned.
1.272 +If the resulting path does not exist, then the operation cannot proceed and the function returns an error code.
1.273 +
1.274 +@param aFs The file server session.
1.275 +@param aFileName The name of the file. Any path components (i.e. drive letter
1.276 + or directory), which are not specified, are taken from
1.277 + the session path.
1.278 +@param aFileMode The mode in which the file is opened. See TFileMode for details.
1.279 +
1.280 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.281 +
1.282 +@see TFileMode
1.283 +@see RFile64::Create()
1.284 +
1.285 +@panic FBuf64 7 In _DEBUG mode - Invalid aFs object (null file session handle).
1.286 +@panic FBuf64 10 In _DEBUG mode - Invalid file name length (zero file name length).
1.287 +*/
1.288 +TInt RFileBuf64::Create(RFs& aFs, const TDesC& aFileName, TUint aFileMode)
1.289 + {
1.290 + __FBUF64_ASSERT(aFs.Handle() != 0, EFBufPanicFsHandle);
1.291 + __FBUF64_ASSERT(aFileName.Length() > 0, EFBufPanicFileNameLen);
1.292 +
1.293 + TInt err = DoPreInit();
1.294 + if(err == KErrNone)
1.295 + {
1.296 + err = iFile.Create(aFs, aFileName, aFileMode);
1.297 + }
1.298 + PROFILE_CREATE(aFileName, err);
1.299 + return DoPostInit(err);
1.300 + }
1.301 +
1.302 +/**
1.303 +Initializes the RFileBuf64 object and opens an existing file that will be accessed through RFileBuf64 public interface.
1.304 +If the file does not already exist, an error is returned.
1.305 +
1.306 +@param aFs The file server session.
1.307 +@param aFileName The name of the file. Any path components (i.e. drive letter
1.308 + or directory), which are not specified, are taken from
1.309 + the session path.
1.310 +@param aFileMode The mode in which the file is opened. See TFileMode for details.
1.311 +
1.312 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.313 +
1.314 +@see TFileMode
1.315 +@see RFile64::Open()
1.316 +
1.317 +@panic FBuf64 7 In _DEBUG mode - Invalid aFs object (null file session handle).
1.318 +@panic FBuf64 10 In _DEBUG mode - Invalid file name length (zero file name length).
1.319 +*/
1.320 +TInt RFileBuf64::Open(RFs& aFs, const TDesC& aFileName, TUint aFileMode)
1.321 + {
1.322 + __FBUF64_ASSERT(aFs.Handle() != 0, EFBufPanicFsHandle);
1.323 + __FBUF64_ASSERT(aFileName.Length() > 0, EFBufPanicFileNameLen);
1.324 +
1.325 + TInt err = DoPreInit();
1.326 + if(err == KErrNone)
1.327 + {
1.328 + err = iFile.Open(aFs, aFileName, aFileMode);
1.329 + }
1.330 + PROFILE_OPEN(aFileName, err);
1.331 + return DoPostInit(err);
1.332 + }
1.333 +
1.334 +/**
1.335 +Initializes the RFileBuf64 object and creates and opens a temporary file with unique name that will be accessed through
1.336 +RFileBuf64 public interface.
1.337 +
1.338 +@param aFs The file server session.
1.339 +@param aPath The directory in which the file is created.
1.340 +@param aFileName On return, contains the full path and file name of the file.
1.341 + The filename is guaranteed to be unique within the directory
1.342 + specified by aPath.
1.343 +@param aFileMode The mode in which the file is opened. The access mode is
1.344 + automatically set to EFileWrite. See TFileMode for details.
1.345 +
1.346 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.347 +
1.348 +@see TFileMode
1.349 +@see RFile64::Temp()
1.350 +
1.351 +@panic FBuf64 7 In _DEBUG mode - Invalid aFs object (null file session handle).
1.352 +*/
1.353 +TInt RFileBuf64::Temp(RFs& aFs, const TDesC& aPath, TFileName& aFileName, TUint aFileMode)
1.354 + {
1.355 + __FBUF64_ASSERT(aFs.Handle() != 0, EFBufPanicFsHandle);
1.356 +
1.357 + TInt err = DoPreInit();
1.358 + if(err == KErrNone)
1.359 + {
1.360 + err = iFile.Temp(aFs, aPath, aFileName, aFileMode);
1.361 + }
1.362 + PROFILE_TEMP(aFileName, err);
1.363 + return DoPostInit(err);
1.364 + }
1.365 +
1.366 +/**
1.367 +Initializes the RFileBuf64 object and creates and adopts an already open file from a client that will be accessed through
1.368 +RFileBuf64 public interface.
1.369 +The client's RFs and RFile or RFile64 handles are contained in message slots within aMsg.
1.370 +Assumes that the client's RFs and RFile or RFile64 handles have been sent to the server using TransferToServer().
1.371 +
1.372 +@param aMsg The message received from the client
1.373 +@param aFsIndex The index that identifies the message slot
1.374 + of a file server session (RFs) handle
1.375 +@param aFileIndex The index that identifies the message slot
1.376 + of the sub-session (RFile or RFile64) handle of the already opened file
1.377 +
1.378 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.379 +
1.380 +@see TFileMode
1.381 +@see RFile64::AdoptFromClient()
1.382 +@see KMaxMessageArguments
1.383 +
1.384 +@panic FBuf64 8 In _DEBUG mode - Invalid aMsg object (null message handle).
1.385 +@panic FBuf64 9 In _DEBUG mode - Invalid file session handle message slot index or invalid file handle message slot index.
1.386 + (Probably negative index or index bigger or equal to KMaxMessageArguments)
1.387 +*/
1.388 +TInt RFileBuf64::AdoptFromClient(const RMessage2& aMsg, TInt aFsIndex, TInt aFileIndex)
1.389 + {
1.390 + __FBUF64_ASSERT(aMsg.Handle() != 0, EFBufPanicMsgHandle);
1.391 + __FBUF64_ASSERT(aFsIndex >= 0 && aFsIndex < KMaxMessageArguments, EFBufPanicMsgIndex);
1.392 + __FBUF64_ASSERT(aFileIndex >= 0 && aFileIndex < KMaxMessageArguments, EFBufPanicMsgIndex);
1.393 +
1.394 + TInt err = DoPreInit();
1.395 + if(err == KErrNone)
1.396 + {
1.397 + err = iFile.AdoptFromClient(aMsg, aFsIndex, aFileIndex);
1.398 + }
1.399 + PROFILE_ADOPT(KNullDesC, err);
1.400 + return DoPostInit(err);
1.401 + }
1.402 +
1.403 +/**
1.404 +Writes to the file the pending data (if the buffer contains pending data), closes the file and releases
1.405 +the RFileBuf64 resources.
1.406 +RFileBuf64::Flush() should be called before RFileBuf64::Close() to ensure that if there are pending data, they will
1.407 +be written to the file and if the operation fails, the caller will be notified with an appropriate return error.
1.408 +
1.409 +@see RFileBuf64::Flush()
1.410 +*/
1.411 +void RFileBuf64::Close()
1.412 + {
1.413 + if(iBase != 0 && iFile.SubSessionHandle() != 0)
1.414 + {
1.415 + (void)DoFileWrite2();
1.416 + }
1.417 + iFile.Close();
1.418 + User::Free(iBase);
1.419 + iBase = 0;
1.420 + PROFILE_CLOSE();
1.421 + }
1.422 +
1.423 +/**
1.424 +Calculates and sets optimal read-ahead buffer size.
1.425 +aBlockSize and aReadRecBufSize values are retrieved by the caller from the file system.
1.426 +
1.427 +Initialization rules:
1.428 +Rule 1: If aReadRecBufSize is positive, bigger than the default read-ahead and
1.429 + a power of two then the read-ahead value will be
1.430 + initialized with aReadRecBufSize (if aReadRecBufSize is less than the buffer capacity otherwise
1.431 + the buffer capacity will be used as a read-ahead value).
1.432 +Rule 2: If rule#1 is not applicable then the same checks, as in rule#1, are performed this time for aBlockSize.
1.433 + If aBlockSize passes the checks then it will be used as a read-ahead value.
1.434 +
1.435 +
1.436 +@param aBlockSize The size of a file block in bytes
1.437 +@param aReadRecBufSize The recommended buffer size for optimised reading performance
1.438 +
1.439 +@return The new read-ahead value
1.440 +
1.441 +@see TVolumeIOParamInfo
1.442 +*/
1.443 +TInt RFileBuf64::SetReadAheadSize(TInt aBlockSize, TInt aReadRecBufSize)
1.444 + {
1.445 + __FILEBUF64_INVARIANT();
1.446 + if((aReadRecBufSize & (aReadRecBufSize - 1)) == 0 && aReadRecBufSize > RFileBuf64::KDefaultReadAheadSize)
1.447 + {
1.448 + iReadAheadSize = aReadRecBufSize > iCapacity ? iCapacity : aReadRecBufSize;
1.449 + }
1.450 + else if((aBlockSize & (aBlockSize - 1)) == 0 && aBlockSize > RFileBuf64::KDefaultReadAheadSize)
1.451 + {
1.452 + iReadAheadSize = aBlockSize > iCapacity ? iCapacity : aBlockSize;
1.453 + }
1.454 + __FILEBUF64_INVARIANT();
1.455 + return iReadAheadSize;
1.456 + }
1.457 +
1.458 +/**
1.459 +Reads from the file at the specified position (aFilePos).
1.460 +If the data to be read is in the buffer, then the data will be taken from the buffer.
1.461 +
1.462 +@param aFilePos Position of first byte to be read. This is an offset from
1.463 + the start of the file.
1.464 + If aPos is beyond the end of the file, the function returns
1.465 + a zero length descriptor.
1.466 +@param aDes Descriptor into which binary data is read. Any existing contents
1.467 + are overwritten. On return, its length is set to the number of
1.468 + bytes read.
1.469 +
1.470 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.471 +
1.472 +@panic FBuf64 4 In _DEBUG mode - negative aFilePos value.
1.473 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.474 +
1.475 +@see RFileBuf64::Invariant()
1.476 +*/
1.477 +TInt RFileBuf64::Read(TInt64 aFilePos, TDes8& aDes)
1.478 + {
1.479 + __FBUF64_ASSERT(aFilePos >= 0, EFBufPanicFilePos);
1.480 + __FILEBUF64_INVARIANT();
1.481 + aDes.SetLength(0);
1.482 + //0. The output buffer max len is 0
1.483 + if(aDes.MaxLength() == 0)
1.484 + {
1.485 + __FILEBUF64_INVARIANT();
1.486 + return KErrNone;
1.487 + }
1.488 + //1. Initialize the "iFileSize" if it is not initialized yet
1.489 + TInt err = DoFileSize();
1.490 + if(err != KErrNone)
1.491 + {
1.492 + __FILEBUF64_INVARIANT();
1.493 + return err;
1.494 + }
1.495 + //2. Optimize the buffer capacity
1.496 + TInt len = aDes.MaxLength();
1.497 + if((err = DoSetCapacity(len)) != KErrNone)
1.498 + {
1.499 + return err;
1.500 + }
1.501 + //3. Too big "read" request - read directly from the file
1.502 + if(len > iCapacity)
1.503 + {
1.504 + if((aFilePos + len) > iFilePos && aFilePos < (iFilePos + iLength))
1.505 + {//Write the pending data if the iDirty flag is set, otherwise preserve the buffer content.
1.506 + err = DoFileWrite1(aFilePos);
1.507 + }
1.508 + if(err == KErrNone)
1.509 + {
1.510 + err = iFile.Read(aFilePos, aDes);
1.511 + PROFILE_READ(aFilePos, aDes.Size(), err);
1.512 + }
1.513 + __FILEBUF64_INVARIANT();
1.514 + return err;
1.515 + }
1.516 + //4. The requested data size is smaller than the buffer capacity
1.517 + TUint8* outptr = const_cast <TUint8*> (aDes.Ptr());
1.518 + while(len > 0 && err == KErrNone && aFilePos < iFileSize)
1.519 + {
1.520 + //1. If part or all of the data is in the buffer - copy the data to the target location
1.521 + if(aFilePos >= iFilePos && aFilePos < (iFilePos + iLength))
1.522 + {
1.523 + TInt blocklen = Min(len, (iFilePos + iLength - aFilePos));
1.524 + outptr = Mem::Copy(outptr, iBase + (aFilePos - iFilePos), blocklen);
1.525 + len -= blocklen;
1.526 + aFilePos += blocklen;
1.527 + }
1.528 + //2. Perform a read-ahead operation
1.529 + else
1.530 + {
1.531 + //Write the pending data if the iDirty flag is set, otherwise preserve the buffer content.
1.532 + err = DoFileWrite1(aFilePos);
1.533 + if(err != KErrNone)
1.534 + {
1.535 + break;
1.536 + }
1.537 + if(iNextReadFilePos != aFilePos)
1.538 + {//Guessed read ahead was wrong. Direct "file read" operation
1.539 + iNextReadFilePosHits = 0;
1.540 + TPtr8 ptr2(outptr, len);
1.541 + err = iFile.Read(aFilePos, ptr2);
1.542 + PROFILE_READ(aFilePos, ptr2.Size(), err);
1.543 + if(err == KErrNone)
1.544 + {
1.545 + iNextReadFilePos = aFilePos + len;
1.546 + len -= ptr2.Length();
1.547 + }
1.548 + break;
1.549 + }
1.550 + //The guessed from the previous "file read" operation file pos is correct. Start reading-ahead.
1.551 + const TInt KMaxReadFilePosHits = 4;//The max read-ahead buffer size can be up to 2^4 times the iReadAheadSize
1.552 + if(iNextReadFilePosHits < KMaxReadFilePosHits)
1.553 + {
1.554 + ++iNextReadFilePosHits;
1.555 + }
1.556 + TInt maxReadAhead = iReadAheadSize * (1 << iNextReadFilePosHits);
1.557 + TInt align = (aFilePos + len + maxReadAhead) & (iReadAheadSize - 1);
1.558 + TInt readahead = maxReadAhead - align;
1.559 + if(readahead < 0)
1.560 + {
1.561 + // if read-ahead doesn't cross block boundary do it all
1.562 + readahead = maxReadAhead;
1.563 + }
1.564 + TPtr8 ptr(iBase, Min(iCapacity, (len + readahead)));
1.565 + err = iFile.Read(aFilePos, ptr);
1.566 + PROFILE_READ(aFilePos, ptr.Size(), err);
1.567 + if(err == KErrNone)
1.568 + {
1.569 + iFilePos = aFilePos;
1.570 + iLength = ptr.Length();
1.571 + iNextReadFilePos = iFilePos + iLength;
1.572 + if(iLength == 0)
1.573 + {
1.574 + break;
1.575 + }
1.576 + }
1.577 + else
1.578 + {
1.579 + DoDiscard();
1.580 + }
1.581 + }
1.582 + }
1.583 + aDes.SetLength(aDes.MaxLength() - len);
1.584 + __FILEBUF64_INVARIANT();
1.585 + return err;
1.586 + }
1.587 +
1.588 +/**
1.589 +Writes to the file at the specified offset (aFilePos) within the file.
1.590 +If certain conditions are met, the data will be stored in the buffer - no call to the file server.
1.591 +
1.592 +@param aFilePos The offset from the start of the file at which the first byte is written.
1.593 + If a position beyond the end of the file is specified, then
1.594 + the write operation begins at the end of the file.
1.595 + If the position has been locked, then the write fails.
1.596 +
1.597 +@param aData The descriptor from which binary data is written. The function writes
1.598 + the entire contents of aData to the file.
1.599 +
1.600 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.601 +
1.602 +@panic FBuf64 4 In _DEBUG mode - negative aFilePos value.
1.603 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.604 +
1.605 +@see RFileBuf64::Invariant()
1.606 +*/
1.607 +TInt RFileBuf64::Write(TInt64 aFilePos, const TDesC8& aData)
1.608 + {
1.609 + __FBUF64_ASSERT(aFilePos >= 0, EFBufPanicFilePos);
1.610 + __FILEBUF64_INVARIANT();
1.611 + if(aData.Length() == 0)
1.612 + {
1.613 + __FILEBUF64_INVARIANT();
1.614 + return KErrNone;
1.615 + }
1.616 + TInt err = DoFileSize();
1.617 + if(err != KErrNone)
1.618 + {
1.619 + __FILEBUF64_INVARIANT();
1.620 + return err;
1.621 + }
1.622 + if((err = DoSetCapacity(aData.Length())) != KErrNone)
1.623 + {
1.624 + return err;
1.625 + }
1.626 + DoDiscardBufferedReadData();
1.627 + const TUint8* data = aData.Ptr();
1.628 + for(TInt len = aData.Length(); len > 0 && err == KErrNone;)
1.629 + {
1.630 + //1. The new write pos is before the buffered file pos
1.631 + if(aFilePos < iFilePos)
1.632 + {
1.633 + //If the new data sticks to/overlapps the old data and there is room in the buffer to move the old data
1.634 + //toward the end, then the new data can be copied at the beginning of the buffer.
1.635 + if((aFilePos + len) >= iFilePos && (iFilePos - aFilePos) <= (iCapacity - iLength))
1.636 + {
1.637 + (void)Mem::Copy(iBase + (iFilePos - aFilePos), iBase, iLength); //Make room - move the existing data toward the end
1.638 + (void)Mem::Copy(iBase, data, len); //of the buffer. Stick the new data to the old data
1.639 + iLength += (iFilePos - aFilePos);
1.640 + iFilePos = aFilePos; //The new file pos is associated with the buffer
1.641 + iFileSize = Max(iFileSize, (iFilePos + iLength));
1.642 + len = 0; //No more new data
1.643 + iDirty = ETrue;
1.644 + }
1.645 + else
1.646 + //The "aFilePos" is too far before the "iFilePos". Write the buffer and associate the new pos with the buffer
1.647 + {
1.648 + err = DoFileWrite2(aFilePos);
1.649 + }
1.650 + }
1.651 + //2. The new write pos is after the associated file pos + the data length.
1.652 + else if(aFilePos > (iFilePos + iLength))
1.653 + {
1.654 + if(aFilePos > iFileSize) //Beyond the end of the file
1.655 + {
1.656 + if((iFilePos + iLength) == iFileSize && (aFilePos - iFilePos) < iCapacity)
1.657 + { //but within the buffer => extend the file with zeros.
1.658 + Mem::FillZ(iBase + iLength, aFilePos - iFilePos - iLength);
1.659 + iLength = aFilePos - iFilePos;
1.660 + iFileSize = Max(iFileSize, (iFilePos + iLength));
1.661 + iDirty = ETrue;
1.662 + }
1.663 + else
1.664 + //Beyond the end of the file and not in the buffer - write the buffer to the file.
1.665 + {
1.666 + err = DoFileWrite2(aFilePos);
1.667 + }
1.668 + }
1.669 + else
1.670 + //Within the file, not in the buffer - write the buffer and associate the new file pos with the buffer
1.671 + {
1.672 + err = DoFileWrite2(aFilePos);
1.673 + }
1.674 + }
1.675 + //3. The new write pos is in the buffer, but the data length is too big
1.676 + // (For SQLite is OK, otherwise the whole block must be written to the file)
1.677 + //4. The new write pos is in the buffer, the data entirely fits in the buffer
1.678 + else
1.679 + {
1.680 + if (iFilePos+iCapacity == aFilePos) //The buffer is full. The new position to write is the end of the buffer.
1.681 + {
1.682 + err = DoFileWrite2(aFilePos);
1.683 + }
1.684 + if(err == KErrNone)
1.685 + {
1.686 + TInt amount = Min(len, (iCapacity - (aFilePos - iFilePos)));
1.687 + const TUint8* end = Mem::Copy(iBase + (aFilePos - iFilePos), data, amount);
1.688 + iLength = Max(iLength, (end - iBase));
1.689 + iFileSize = Max(iFileSize, (iFilePos + iLength));
1.690 + len -= amount;
1.691 + data += amount;
1.692 + aFilePos += amount;
1.693 + iDirty = ETrue;
1.694 + }
1.695 + }
1.696 + }
1.697 + __FILEBUF64_INVARIANT();
1.698 + return err;
1.699 + }
1.700 +
1.701 +/**
1.702 +Gets the current file size.
1.703 +
1.704 +@param aFileSize On return, the size of the file in bytes.
1.705 +
1.706 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.707 +
1.708 +See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
1.709 +
1.710 +@see RFileBuf64::Invariant()
1.711 +*/
1.712 +TInt RFileBuf64::Size(TInt64& aFileSize)
1.713 + {
1.714 + __FILEBUF64_INVARIANT();
1.715 + TInt err = DoFileSize();
1.716 + if(err == KErrNone)
1.717 + {
1.718 + aFileSize = iFileSize;
1.719 + }
1.720 + __FILEBUF64_INVARIANT();
1.721 + return err;
1.722 + }
1.723 +
1.724 +/**
1.725 +Sets the file size.
1.726 +
1.727 +If the size of the file is reduced, data may be lost from the end of the file.
1.728 +
1.729 +Note:
1.730 +
1.731 +1. The current file position remains unchanged unless SetSize() reduces the size
1.732 + of the file in such a way that the current file position is now beyond
1.733 + the end of the file. In this case, the current file position is set to
1.734 + the end of file.
1.735 +
1.736 +2. If the file was not opened for writing, an error is returned.
1.737 +
1.738 +@param aFileSize The new size of the file, in bytes. This value must not be negative, otherwise the function raises a panic.
1.739 +
1.740 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.741 +
1.742 +@panic FBuf64 5 In _DEBUG mode - negative aFileSize value.
1.743 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.744 +
1.745 +@see RFileBuf64::Invariant()
1.746 +*/
1.747 +TInt RFileBuf64::SetSize(TInt64 aFileSize)
1.748 + {
1.749 + __FBUF64_ASSERT(aFileSize >= 0, EFBufPanicFileSize);
1.750 + __FILEBUF64_INVARIANT();
1.751 + return DoSetFileSize(aFileSize);
1.752 + }
1.753 +
1.754 +/**
1.755 +Writes the pending data and then flushes the file.
1.756 +
1.757 +Although RFileBuf64::Close() also flushes internal buffers, it is better
1.758 +to call RFileBuf64::Flush() before the file is closed. This is because Close() returns no
1.759 +error information, so there is no way of telling whether the final data was
1.760 +written to the file successfully or not.
1.761 +
1.762 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.763 +
1.764 +See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
1.765 +
1.766 +@see RFileBuf64::Invariant()
1.767 +*/
1.768 +TInt RFileBuf64::Flush()
1.769 + {
1.770 + __FILEBUF64_INVARIANT();
1.771 + return DoFileFlush();
1.772 + }
1.773 +
1.774 +/**
1.775 +Gets information about the drive on which this file resides.
1.776 +
1.777 +@param aDriveNumber On return, the drive number.
1.778 +
1.779 +@param aDriveInfo On return, contains information describing the drive
1.780 + and the medium mounted on it. The value of TDriveInfo::iType
1.781 + shows whether the drive contains media.
1.782 +
1.783 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.784 +
1.785 +See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
1.786 +
1.787 +@see RFileBuf64::Invariant()
1.788 +*/
1.789 +TInt RFileBuf64::Drive(TInt& aDriveNumber, TDriveInfo& aDriveInfo) const
1.790 + {
1.791 + __FILEBUF64_INVARIANT();
1.792 + return iFile.Drive(aDriveNumber, aDriveInfo);
1.793 + }
1.794 +
1.795 +/**
1.796 +Initializes RFileBuf64 data members with their initial values.
1.797 +Allocates memory for the file buffer.
1.798 +
1.799 +@return KErrNone if successful,
1.800 + KErrNoMemory out of memory;
1.801 +*/
1.802 +TInt RFileBuf64::DoPreInit()
1.803 + {
1.804 + DoDiscard();
1.805 + iReadAheadSize = RFileBuf64::KDefaultReadAheadSize;
1.806 + iBase = static_cast <TUint8*> (User::Alloc(iCapacity));
1.807 + return iBase ? KErrNone : KErrNoMemory;
1.808 + }
1.809 +
1.810 +/**
1.811 +Performs post-initialization of the RFileBuf64 object.
1.812 +If aInitErr is not KErrNone, then the buffer memory will be released.
1.813 +The function returns the aInitErr value to the caller.
1.814 +
1.815 +@param aInitErr The result of the performed before the call RFileBuf64 initialization.
1.816 +
1.817 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.818 +*/
1.819 +TInt RFileBuf64::DoPostInit(TInt aInitErr)
1.820 + {
1.821 + if(aInitErr != KErrNone)
1.822 + {
1.823 + User::Free(iBase);
1.824 + iBase = 0;
1.825 + }
1.826 + return aInitErr;
1.827 + }
1.828 +
1.829 +/**
1.830 +Discards the content of the RFileBuf64 object returning it to the state as if it has just been created.
1.831 +*/
1.832 +void RFileBuf64::DoDiscard()
1.833 + {
1.834 + iLength = 0;
1.835 + iFilePos = 0;
1.836 + iFileSize = KFileSizeNotSet;
1.837 + iDirty = EFalse;
1.838 + iNextReadFilePos = KNextReadFilePosNotSet;
1.839 + iNextReadFilePosHits = 0;
1.840 + }
1.841 +
1.842 +/**
1.843 +Gets the current file size.
1.844 +If iFileSize value is valid, then no call to the file server will be made.
1.845 +Otherwise the file server will be called and the file size - stored (cached) in iFileSize data member for later use.
1.846 +
1.847 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.848 +
1.849 +See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
1.850 +
1.851 +@see RFileBuf64::Invariant()
1.852 +*/
1.853 +TInt RFileBuf64::DoFileSize()
1.854 + {
1.855 + __FILEBUF64_INVARIANT();
1.856 + if(iFileSize != KFileSizeNotSet)
1.857 + {
1.858 + __FILEBUF64_INVARIANT();
1.859 + return KErrNone;
1.860 + }
1.861 + TInt err = iFile.Size(iFileSize);
1.862 + PROFILE_SIZE(iFileSize, err);
1.863 + if(err != KErrNone)
1.864 + {
1.865 + DoDiscard();
1.866 + }
1.867 + else
1.868 + {
1.869 + iRealFileSize = iFileSize;
1.870 + }
1.871 + __FILEBUF64_INVARIANT();
1.872 + return err;
1.873 + }
1.874 +
1.875 +/**
1.876 +Sets the file size.
1.877 +If the buffer contains pending data, the data will be written to the file
1.878 +before the "set file size" operation, if certain conditions are met.
1.879 +
1.880 +@param aFileSize The new size of the file, in bytes. This value must not be negative, otherwise the function raises a panic.
1.881 +
1.882 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.883 +
1.884 +@panic FBuf64 5 In _DEBUG mode - negative aFileSize value.
1.885 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.886 +
1.887 +@see RFileBuf64::Invariant()
1.888 +*/
1.889 +TInt RFileBuf64::DoSetFileSize(TInt64 aFileSize)
1.890 + {
1.891 + __FBUF64_ASSERT(aFileSize >= 0, EFBufPanicFileSize);
1.892 + __FILEBUF64_INVARIANT();
1.893 + if(aFileSize < iFilePos)
1.894 + {
1.895 + iDirty = EFalse;
1.896 + iLength = 0;
1.897 + }
1.898 + //If the new file size is "in" the buffer then change the "iLength"
1.899 + else if(aFileSize < (iFilePos + iLength))
1.900 + {
1.901 + iLength = aFileSize - iFilePos;
1.902 + }
1.903 + TInt err = iFile.SetSize(aFileSize);
1.904 + PROFILE_SETSIZE(aFileSize, err);
1.905 + if(err != KErrNone)
1.906 + {
1.907 + DoDiscard();
1.908 + }
1.909 + else
1.910 + {
1.911 + iFileSize = aFileSize;
1.912 + iRealFileSize = aFileSize;
1.913 + }
1.914 + __FILEBUF64_INVARIANT();
1.915 + return err;
1.916 + }
1.917 +
1.918 +/**
1.919 +Writes the pending data and flushes the file.
1.920 +
1.921 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.922 +
1.923 +See RFileBuf64::Invariant() for possible panics that may occur when this method is called.
1.924 +
1.925 +@see RFileBuf64::Invariant()
1.926 +*/
1.927 +TInt RFileBuf64::DoFileFlush()
1.928 + {
1.929 + __FILEBUF64_INVARIANT();
1.930 + TInt err = DoFileWrite2();//Write the buffer if the iDirty flag is set. Do not preserve the buffer content and file pos.
1.931 + if(err != KErrNone)
1.932 + {
1.933 + __FILEBUF64_INVARIANT();
1.934 + return err;
1.935 + }
1.936 + err = iFile.Flush();
1.937 + PROFILE_FLUSH(err);
1.938 + if(err != KErrNone)
1.939 + {
1.940 + DoDiscard();
1.941 + }
1.942 + iLength = 0;
1.943 + __FILEBUF64_INVARIANT();
1.944 + return err;
1.945 + }
1.946 +
1.947 +/**
1.948 +Writes the buffered data to the file if the iLength value is > 0.
1.949 +If the file write operation extends the file, the iFileSize data member will be initialized with the new file size.
1.950 +No changes occur in the other data member values.
1.951 +
1.952 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.953 +
1.954 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.955 +
1.956 +@see RFileBuf64::DoFileWrite1()
1.957 +@see RFileBuf64::DoFileWrite2()
1.958 +@see RFileBuf64::Invariant()
1.959 +*/
1.960 +TInt RFileBuf64::DoFileWrite()
1.961 + {
1.962 + __FILEBUF64_INVARIANT();
1.963 + if(iLength == 0)
1.964 + {
1.965 + __FILEBUF64_INVARIANT();
1.966 + return KErrNone;
1.967 + }
1.968 + TPtrC8 data(iBase, iLength);
1.969 + TInt err = KErrNone;
1.970 + if(iFilePos > iRealFileSize )
1.971 + {
1.972 + err = DoSetFileSize(iFileSize);
1.973 + }
1.974 + if(err == KErrNone)
1.975 + {
1.976 + err = iFile.Write(iFilePos, data);
1.977 + }
1.978 + PROFILE_WRITE(iFilePos, iLength, err);
1.979 + if(err == KErrNone)
1.980 + {
1.981 + iRealFileSize = iFileSize;
1.982 + }
1.983 + else
1.984 + {
1.985 + DoDiscard();
1.986 + }
1.987 + __FILEBUF64_INVARIANT();
1.988 + return err;
1.989 + }
1.990 +
1.991 +/**
1.992 +Writes the buffered data to the file if the iDirty flag is set.
1.993 +If the iDirty flag is set and the file write operation was successful, the iFilePos will be initialized with
1.994 +the aNewFilePos value, the iLength will be set to 0.
1.995 +This method is called from RFileBuf64::Read(), where:
1.996 + - if the buffer contains cached writes (iDirty flag is set), the buffer has to be flushed and iFilePos initialized
1.997 + with aNewFilePos - the offset in the file where the next file read operation should start from;
1.998 + - if the buffer contains cached reads, then nothing happens, the buffer content will be kept;
1.999 +The function resets the iDirty flag.
1.1000 +
1.1001 +@param aNewFilePos If the buffer is successfully written to the file the iFilePos data member will be initialized with
1.1002 + the aNewFilePos value.
1.1003 +
1.1004 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.1005 +
1.1006 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.1007 +
1.1008 +@panic FBuf64 4 In _DEBUG mode - negative aNewFilePos value.
1.1009 +
1.1010 +@see RFileBuf64::Read()
1.1011 +@see RFileBuf64::DoFileWrite()
1.1012 +@see RFileBuf64::DoFileWrite2()
1.1013 +@see RFileBuf64::Invariant()
1.1014 +*/
1.1015 +TInt RFileBuf64::DoFileWrite1(TInt64 aNewFilePos)
1.1016 + {
1.1017 + __FBUF64_ASSERT(aNewFilePos >= 0, EFBufPanicFilePos);
1.1018 + __FILEBUF64_INVARIANT();
1.1019 + TInt err = KErrNone;
1.1020 + if(iDirty)
1.1021 + {
1.1022 + err = DoFileWrite();
1.1023 + if(err == KErrNone)
1.1024 + {
1.1025 + iFilePos = aNewFilePos;
1.1026 + iLength = 0;
1.1027 + }
1.1028 + }
1.1029 + iDirty = EFalse;
1.1030 + __FILEBUF64_INVARIANT();
1.1031 + return err;
1.1032 + }
1.1033 +
1.1034 +/*
1.1035 +Writes the buffered data to the file if the iDirty flag is set.
1.1036 +If the file write operation was successful or if the iDirty flag was not set, the iFilePos will be initialized with
1.1037 +the aNewFilePos value, the iLength will be set to 0.
1.1038 +This method is called from RFileBuf64::Write() an other RFileBuf64 methods (but not from RFileBuf64::Read()), where:
1.1039 + - if the buffer contains cached writes (iDirty flag is set), the buffer has to be flushed and iFilePos initialized
1.1040 + with aNewFilePos - the offset in the file for which the write data will be cached in the buffer;
1.1041 + - if the buffer contains cached reads, then the buffer content will be destroyed, iFilePos initialized with aNewFilePos
1.1042 + and iLength set to 0;
1.1043 +The function resets the iDirty flag.
1.1044 +The difference between RFileBuf64::DoFileWrite1() and RFileBuf64::DoFileWrite2() is:
1.1045 + - RFileBuf64::DoFileWrite1() perserves the buffer content if iDirty is not set;
1.1046 + - RFileBuf64::DoFileWrite2() always destroys the buffer content and initializes iFilePos;
1.1047 +
1.1048 +@param aNewFilePos If the buffer is successfully written to the file the iFilePos data member will be initialized with
1.1049 + the aNewFilePos value.
1.1050 +
1.1051 +@return KErrNone if successful, otherwise one of the other system-wide error codes.
1.1052 +
1.1053 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.1054 +
1.1055 +@panic FBuf64 4 In _DEBUG mode - negative aNewFilePos value.
1.1056 +
1.1057 +@see RFileBuf64::Write()
1.1058 +@see RFileBuf64::DoFileWrite()
1.1059 +@see RFileBuf64::DoFileWrite1()
1.1060 +@see RFileBuf64::Invariant()
1.1061 +*/
1.1062 +TInt RFileBuf64::DoFileWrite2(TInt64 aNewFilePos)
1.1063 + {
1.1064 + __FBUF64_ASSERT(aNewFilePos >= 0, EFBufPanicFilePos);
1.1065 + __FILEBUF64_INVARIANT();
1.1066 + TInt err = KErrNone;
1.1067 + if(iDirty)
1.1068 + {
1.1069 + err = DoFileWrite();
1.1070 + }
1.1071 + if(err == KErrNone)
1.1072 + {
1.1073 + iFilePos = aNewFilePos;
1.1074 + iLength = 0;
1.1075 + }
1.1076 + iDirty = EFalse;
1.1077 + __FILEBUF64_INVARIANT();
1.1078 + return err;
1.1079 + }
1.1080 +
1.1081 +/**
1.1082 +This function discards the buffer content if the buffer contains cached read data.
1.1083 +The function is called from RFileBuf64::Write(), because if the buffer contains cached read data,
1.1084 +they cannot be mixed with the cached write data.
1.1085 +Reason: for example the buffer contains 8Kb cached read data from file offset 0.
1.1086 + The data write request is 10 bytes at offset 4000. The write data will be cached,
1.1087 + because the buffer contains data from from this file area: [0..8192].
1.1088 + The iDirty flag will be set. Later when RFileBuf64::Flush() is called, the whole
1.1089 + 8Kb buffer will be written. There is nothing wrong with that, the file content will be consistent.
1.1090 + But from performance point of view: 8Kb written vs. 10 bytes written - that may badly impact the performance.
1.1091 +
1.1092 +@see RFileBuf64::Write()
1.1093 +
1.1094 +See RFileBuf64::Invariant() for other possible panics that may occur when this method is called.
1.1095 +*/
1.1096 +void RFileBuf64::DoDiscardBufferedReadData()
1.1097 + {
1.1098 + __FILEBUF64_INVARIANT();
1.1099 + if(!iDirty && iLength > 0)
1.1100 + {
1.1101 + iLength = 0;
1.1102 + iFilePos = 0;
1.1103 + iNextReadFilePos = KNextReadFilePosNotSet;
1.1104 + iNextReadFilePosHits = 0;
1.1105 + }
1.1106 + __FILEBUF64_INVARIANT();
1.1107 + }
1.1108 +
1.1109 +/**
1.1110 +Sets the most appropriate buffer capacity based on the database page size.
1.1111 +The function does a lazy evaluation. The first time the function is called and
1.1112 +aRwDataLength parameter is recognized to be a database or journal page size, the new (optimal)
1.1113 +buffer capacity is calculated and set. All next DoSetCapacity() calls will detect that the new
1.1114 +capacity is already set and will return KErrNone.
1.1115 +
1.1116 +@param aRwDataLength The length of the data being read or written.
1.1117 +@return KErrNone The new capacity was set successfully,
1.1118 + KErrNoMemory Out of memory.
1.1119 +*/
1.1120 +TInt RFileBuf64::DoSetCapacity(TInt aRwDataLength)
1.1121 + {
1.1122 + const TInt KMinPageCount = 4;//the buffer capacity should be at least (KMinPageCount * page size)
1.1123 + //but not less than the original capacity.
1.1124 + const TInt KDefaultPageSize = 1024;//The journal header size is equal to 512 bytes, so it is not easy
1.1125 + //to detect the 512 bytes page size.
1.1126 +
1.1127 + __FBUF64_ASSERT(aRwDataLength > 0, EFBufPanicRwDataLength);
1.1128 + __FILEBUF64_INVARIANT();
1.1129 + if(iOptimized)
1.1130 + {
1.1131 + __FILEBUF64_INVARIANT();
1.1132 + return KErrNone;
1.1133 + }
1.1134 + if((aRwDataLength & (aRwDataLength - 1)) != 0 || aRwDataLength < KDefaultPageSize)
1.1135 + {
1.1136 + __FILEBUF64_INVARIANT();
1.1137 + return KErrNone;
1.1138 + }
1.1139 + //Here: aRwDataLength is power of 2 and is bigger than the default db page size.
1.1140 + //aRwDataLength is the size of the db page.
1.1141 + const TInt pageSize = aRwDataLength;
1.1142 + TInt cnt = iCapacity / pageSize;//how many pages can fit in the buffer now
1.1143 + TInt pageCount = Max(cnt, KMinPageCount);//the number of pages that should fit in the new buffer
1.1144 + TInt newBufCapacity = pageCount * pageSize;
1.1145 + if(newBufCapacity != iCapacity)
1.1146 + {
1.1147 + TUint8* newBase = static_cast <TUint8*> (User::ReAlloc(iBase, newBufCapacity));
1.1148 + if(!newBase)
1.1149 + {
1.1150 + __FILEBUF64_INVARIANT();
1.1151 + return KErrNoMemory;
1.1152 + }
1.1153 + iBase = newBase;
1.1154 + iCapacity = newBufCapacity;
1.1155 + //Adjust the initial read-ahead size to be multiple of the page size.
1.1156 + if((iReadAheadSize % pageSize) != 0)
1.1157 + {
1.1158 + TInt q = iReadAheadSize / pageSize;
1.1159 + iReadAheadSize = q != 0 ? pageSize * q : pageSize;
1.1160 + }
1.1161 + }
1.1162 + iOptimized = ETrue;
1.1163 + __FILEBUF64_INVARIANT();
1.1164 + return KErrNone;
1.1165 + }
1.1166 +
1.1167 +#ifdef _DEBUG
1.1168 +
1.1169 +/**
1.1170 +RFileBuf64 invariant. Called in _DEBUG mode at the beginning and before the end of every RFileBuf64 method
1.1171 +(except the init/destroy methods).
1.1172 +
1.1173 +@panic FBuf64 11 In _DEBUG mode - null "this" pointer.
1.1174 +@panic FBuf64 1 In _DEBUG mode - negative iCapacity value.
1.1175 +@panic FBuf64 2 In _DEBUG mode - the buffer pointer is null (possible the buffer is not allocated or already destroyed).
1.1176 +@panic FBuf64 3 In _DEBUG mode - invalid iLength value (negative or bigger than iCapacity).
1.1177 +@panic FBuf64 4 In _DEBUG mode - negative iFilePos value.
1.1178 +@panic FBuf64 5 In _DEBUG mode - set but negative iFileSize value.
1.1179 +@panic FBuf64 6 In _DEBUG mode - null file handle (the RFile64 object is not created or already destroyed).
1.1180 +@panic FBuf64 13 In _DEBUG mode - set but negative iNextReadFilePos value.
1.1181 +@panic FBuf64 14 In _DEBUG mode - negative iNextReadFilePosHits value.
1.1182 +@panic FBuf64 15 In _DEBUG mode - iReadAheadSize is negative or is bigger than iCapacity.
1.1183 +*/
1.1184 +void RFileBuf64::Invariant() const
1.1185 + {
1.1186 + __FBUF64_ASSERT(this != 0, EFBufPanicNullThis);
1.1187 + __FBUF64_ASSERT(iCapacity > 0, EFBufPanicCapacity);
1.1188 + __FBUF64_ASSERT(iBase != 0, EFBufPanicNullBuf);
1.1189 + __FBUF64_ASSERT(iLength >= 0 && iLength <= iCapacity, EFBufPanicBufLen);
1.1190 + __FBUF64_ASSERT(iFilePos >= 0, EFBufPanicFilePos);
1.1191 + __FBUF64_ASSERT(iFileSize == KFileSizeNotSet || iFileSize >= 0, EFBufPanicFileSize);
1.1192 + __FBUF64_ASSERT(iFile.SubSessionHandle() != 0, EFBufPanicFileHandle);
1.1193 + __FBUF64_ASSERT(iNextReadFilePos == KNextReadFilePosNotSet || iNextReadFilePos >= 0, EFBufPanicNextReadFilePos);
1.1194 + __FBUF64_ASSERT(iNextReadFilePosHits >= 0, EFBufPanicNextReadFilePosHits);
1.1195 + __FBUF64_ASSERT(iReadAheadSize > 0, EFBufPanicFileBlockSize);
1.1196 + }
1.1197 +
1.1198 +#endif