|
1 // Copyright (c) 2008-2009 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 #ifndef FILEBUF64_H |
|
16 #define FILEBUF64_H |
|
17 |
|
18 #include <f32file.h> |
|
19 #include <f32file64.h> |
|
20 |
|
21 //Forward declaration |
|
22 struct MFileInitializer64; |
|
23 |
|
24 /** |
|
25 The RFileBuf64 class provides buffered file read/write operations on a single RFile64 object. |
|
26 RFileBuf64::Read() and RFileBuf64::Write() methods may boost the performance of the read/write file operations up to 30% |
|
27 if compared to their RFile64 equivalents. Especially this is true in the case of a set of sequential read or write |
|
28 operations when the file offset of operation N+1 is the end file offset of operation N plus one byte. |
|
29 |
|
30 The RFileBuf64 public methods declarations match the declarations of the most often used RFile64 public methods. |
|
31 That makes the source code migration from RFile64 to RFileBuf64 easier (or from RFileBuf64 to RFile64). |
|
32 |
|
33 The RFileBuf64 capabilities are similar to those of the RFileBuf class, except the fact that RFileBuf |
|
34 uses 32-bit file offsets, RFileBuf64 uses 64-bit file offsets and RFileBuf64 provides optimised read-ahead operations, |
|
35 crafted especially for the case when RFileBuf64 is used with a page based database management system (like SQLite). |
|
36 |
|
37 Usage notes: |
|
38 @code |
|
39 - an object of RFileBuf64 type must be defined first, specifying the max size (capacity) of the buffer as a parameter |
|
40 of the constructor: |
|
41 |
|
42 RFileBuf64 fbuf(<N>);//<N> is the buffer capacity in bytes |
|
43 |
|
44 - the second step is to initialize the just defined RFileBuf64 object by calling one of the "resource acquisition" |
|
45 methods: RFileBuf64::Create(), RFileBuf64::Open(), RFileBuf64::Temp() or RFileBuf64::AdoptFromClient(). |
|
46 |
|
47 In details, to create a file and access it through a RFileBuf64 object: |
|
48 |
|
49 RFs fs; |
|
50 //initialize the file session |
|
51 ... |
|
52 RFileBuf64 fbuf(<N>); //<N> is the buffer capacity in bytes |
|
53 TInt err = fbuf.Create(fs, <file name>, <file mode>); |
|
54 //check the error |
|
55 |
|
56 To open an existing file and access it through a RFileBuf64 object: |
|
57 |
|
58 RFs fs; |
|
59 //initialize the file session |
|
60 ... |
|
61 RFileBuf64 fbuf(<N>); //<N> is the buffer capacity in bytes |
|
62 TInt err = fbuf.Open(fs, <file name>, <file mode>); |
|
63 //check the error |
|
64 |
|
65 To create a temporary file and access it through a RFileBuf64 object: |
|
66 |
|
67 RFs fs; |
|
68 //initialize the file session |
|
69 ... |
|
70 RFileBuf64 fbuf(<N>); //<N> is the buffer capacity in bytes |
|
71 TInt err = fbuf.Temp(fs, <path>, <file name>, <file mode>); |
|
72 //check the error |
|
73 |
|
74 To open a file from handle and access it through a RFileBuf64 object: |
|
75 |
|
76 RFs fs; |
|
77 //initialize the file session |
|
78 ... |
|
79 RFileBuf64 fbuf(<N>); //<N> is the buffer capacity in bytes |
|
80 TInt err = fbuf.AdoptFromClient(<msg>, <fs handle index>, <file handle index>); |
|
81 //check the error |
|
82 |
|
83 - if the RFileBuf64 object is initialised successfully, now the public RFileBuf64 methods can be called to perform |
|
84 requested operations on the file: |
|
85 |
|
86 err = fbuf.Write(<file pos>, <data>); |
|
87 //check the error |
|
88 .... |
|
89 err = fbuf.Read(<file pos>, <buf>); |
|
90 //check the error |
|
91 .... |
|
92 Note: do not forget to call RFileBuf64::Flush() at the moment when you want to ensure that the file data |
|
93 (possibly buffered) is really written to the file. |
|
94 |
|
95 - The final step is to close the RFileBuf64 object and the corresponding file thus realising the used resouces: |
|
96 |
|
97 fbuf.Close(); |
|
98 |
|
99 @endcode |
|
100 |
|
101 Implementation notes: the current RFileBuf64 implementation is optimised for use by the SQLite OS porting layer. |
|
102 After a detailed investigation of the performed by SQLite file read/write operations it was found that buffering of |
|
103 two or more logical file writes into a single physical file write has a positive impact (as expected) on the performance |
|
104 of the database write operations. But the picture is quite different for the file read operations. The database data is |
|
105 organised in pages with fixed size. After a database is created and set of insert/update/delete operations is performed |
|
106 on it, after a while the database pages (identified by their numbers) are not sequential in the database file and using |
|
107 a read-ahead buffer with fixed size makes no sense because for each "page read" request of N bytes, the RFileBuf64 object |
|
108 will read up to K bytes, K >= N, where K is the read-ahead value in bytes. Since the "read page" requests in general are |
|
109 not sequential (relatively to the page numbers), obviously the read-ahead data is wasted and the "read page" performance |
|
110 is negatively impacted. This observation is true in general except two cases: |
|
111 - sequential scan of a database table; |
|
112 - reading of a BLOB column; |
|
113 In these two cases it is likely that the table/blob data occupies pages with sequential numbers located in a continuous |
|
114 file area. Then if a read-ahead buffer is used that will have a positive impact on the "read page" performance, because |
|
115 the number of the read IPC calls to the file server will be reduced. |
|
116 In order to satisfy those two orthogonal requirements, the RFileBuf64 implementation uses a "read file offset prediction" |
|
117 algorithm: |
|
118 - The file buffer object is created with 0 read-ahead value; |
|
119 - After each "file read" operation the buffer implementation "guesses" what might be the file offset of the |
|
120 next file read operation (it is possible because the database data is organised in pages with fixed size and |
|
121 generally all "file read" requests are for reading a database page) and stores the value in one of its data members; |
|
122 - If the file offset of the next file read operation matches the "guessed" offset, the read-ahead value is changed from |
|
123 0 to 1024 bytes (1024 bytes is the default database page size); |
|
124 - Every next match of the "guessed" file offset value doubles the read-ahead value. But the max read-ahead value is |
|
125 capped by the capacity of the buffer; |
|
126 - If the file offset of the next file read operation does not match the "guessed" file offset, then the read-ahead |
|
127 value is set back to 0; |
|
128 Shortly, depending of the nature of the file read requests, the RFileBuf64 object will dynamically change the read-ahead |
|
129 value thus minimising the amount of the wasted read data and improving the "file read" performance in general. |
|
130 |
|
131 @see RFile64 |
|
132 @see RFileBuf |
|
133 |
|
134 @internalComponent |
|
135 */ |
|
136 class RFileBuf64 |
|
137 { |
|
138 friend void SetReadAheadSizeTest(); |
|
139 |
|
140 enum {KDefaultReadAheadSize = 1024};//Default size in bytes of the read-ahead buffer |
|
141 |
|
142 public: |
|
143 RFileBuf64(TInt aSize); |
|
144 |
|
145 TInt Create(RFs& aFs, const TDesC& aFileName, TUint aFileMode); |
|
146 TInt Open(RFs& aFs, const TDesC& aFileName, TUint aFileMode); |
|
147 TInt Temp(RFs& aFs, const TDesC& aPath, TFileName& aFileName, TUint aFileMode); |
|
148 TInt AdoptFromClient(const RMessage2& aMsg, TInt aFsIndex, TInt aFileIndex); |
|
149 void Close(); |
|
150 TInt SetReadAheadSize(TInt aBlockSize, TInt aReadRecBufSize); |
|
151 |
|
152 TInt Read(TInt64 aFilePos, TDes8& aDes); |
|
153 TInt Write(TInt64 aFilePos, const TDesC8& aData); |
|
154 |
|
155 TInt Size(TInt64& aFileSize); |
|
156 TInt SetSize(TInt64 aFileSize); |
|
157 TInt Flush(); |
|
158 |
|
159 TInt Drive(TInt& aDriveNumber, TDriveInfo& aDriveInfo) const; |
|
160 |
|
161 private: |
|
162 void Invariant() const; |
|
163 TInt DoInit(MFileInitializer64& aFileInitializer); |
|
164 void DoDiscard(); |
|
165 TInt DoFileSize(); |
|
166 TInt DoSetFileSize(TInt64 aFileSize); |
|
167 TInt DoFileFlush(); |
|
168 TInt DoFileWrite(); |
|
169 TInt DoFileWrite1(TInt64 aNewFilePos); |
|
170 TInt DoFileWrite2(TInt64 aNewFilePos = 0LL); |
|
171 void DoDiscardBufferedReadData(); |
|
172 |
|
173 private: |
|
174 //Buffer related |
|
175 const TInt iCapacity; //The buffer size. Indicates how much data can be put in. |
|
176 TUint8* iBase; //Pointer to the beginning of the buffer. |
|
177 TInt iLength; //The length of the data currently held in the buffer. |
|
178 //File related |
|
179 TInt64 iFilePos; //The file position associated with the beginning of the buffer. |
|
180 TInt64 iFileSize; //The file size. |
|
181 RFile64 iFile; //The file object. |
|
182 //Read-ahead related |
|
183 TBool iDirty; //The buffer contains pending data to be written to the file |
|
184 TInt64 iNextReadFilePos; //The guessed file position of the next "file read" operation |
|
185 TInt iNextReadFilePosHits; //How many times the guessed file position of the "file read" operation was correct |
|
186 TInt iReadAheadSize; |
|
187 |
|
188 //Profiler related |
|
189 #ifdef _SQLPROFILER |
|
190 public: |
|
191 void ProfilerReset(); |
|
192 |
|
193 TInt iFileReadCount; //The number of the non-buffered file reads (RFile64::Read() calls). |
|
194 TInt64 iFileReadAmount; //The amount of the data read from the file. |
|
195 TInt iFileWriteCount; //The number of the non-buffered file writes (RFile64::Write() calls). |
|
196 TInt64 iFileWriteAmount; //The amount of the data written to the file. |
|
197 TInt iFileSizeCount; //The number of non-buffered RFile64::Size() calls. |
|
198 TInt iFileSetSizeCount; //The number of non-buffered RFile64::SetSize() calls. |
|
199 TInt iFileFlushCount; //The number of RFile64::Flush() calls. |
|
200 #endif |
|
201 |
|
202 }; |
|
203 |
|
204 #endif//FILEBUF64_H |