193 EFBufPanicNullThis, |
193 EFBufPanicNullThis, |
194 EFBufPanicDirty, |
194 EFBufPanicDirty, |
195 EFBufPanicNextReadFilePos, |
195 EFBufPanicNextReadFilePos, |
196 EFBufPanicNextReadFilePosHits, |
196 EFBufPanicNextReadFilePosHits, |
197 EFBufPanicFileBlockSize, //15 |
197 EFBufPanicFileBlockSize, //15 |
|
198 EFBufPanicRwDataLength, |
198 }; |
199 }; |
199 |
200 |
200 /** |
201 /** |
201 Helper function used in the implementation of the __FBUF64_ASSERT() macro. |
202 Helper function used in the implementation of the __FBUF64_ASSERT() macro. |
202 In case if the expression in __FBUF64_ASSERT() macro evaluates to false, |
203 In case if the expression in __FBUF64_ASSERT() macro evaluates to false, |
247 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
248 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
248 |
249 |
249 /** |
250 /** |
250 Initializes RFileBuf64 data members with their default values. |
251 Initializes RFileBuf64 data members with their default values. |
251 |
252 |
252 @param aSize Max file buffer size (capacity) in bytes. |
253 @param aMinCapacity Minimal file buffer size (capacity) in bytes. |
253 |
254 |
254 @panic FBuf64 1 In _DEBUG mode - aSize is 0 or negative. |
255 @panic FBuf64 1 In _DEBUG mode - aMinCapacity is 0 or negative. |
255 */ |
256 */ |
256 RFileBuf64::RFileBuf64(TInt aSize) : |
257 RFileBuf64::RFileBuf64(TInt aMinCapacity) : |
257 iCapacity(aSize), |
258 iCapacity(aMinCapacity), |
258 iReadAheadSize(RFileBuf64::KDefaultReadAheadSize) |
259 iReadAheadSize(RFileBuf64::KDefaultReadAheadSize), |
259 { |
260 iOptimized(EFalse) |
260 __FBUF64_ASSERT(aSize > 0, EFBufPanicCapacity); |
261 { |
|
262 __FBUF64_ASSERT(aMinCapacity > 0, EFBufPanicCapacity); |
261 } |
263 } |
262 |
264 |
263 /** |
265 /** |
264 Initializes the RFileBuf64 object and creates and opens a new file that will be accessed through RFileBuf64 public interface. |
266 Initializes the RFileBuf64 object and creates and opens a new file that will be accessed through RFileBuf64 public interface. |
265 If the file already exists, an error is returned. |
267 If the file already exists, an error is returned. |
471 TInt RFileBuf64::Read(TInt64 aFilePos, TDes8& aDes) |
473 TInt RFileBuf64::Read(TInt64 aFilePos, TDes8& aDes) |
472 { |
474 { |
473 __FBUF64_ASSERT(aFilePos >= 0, EFBufPanicFilePos); |
475 __FBUF64_ASSERT(aFilePos >= 0, EFBufPanicFilePos); |
474 __FILEBUF64_INVARIANT(); |
476 __FILEBUF64_INVARIANT(); |
475 aDes.SetLength(0); |
477 aDes.SetLength(0); |
476 //1. The output buffer max len is 0 |
478 //0. The output buffer max len is 0 |
477 if(aDes.MaxLength() == 0) |
479 if(aDes.MaxLength() == 0) |
478 { |
480 { |
479 __FILEBUF64_INVARIANT(); |
481 __FILEBUF64_INVARIANT(); |
480 return KErrNone; |
482 return KErrNone; |
481 } |
483 } |
482 //2. Initialize the "iFileSize" if it is not initialized yet |
484 //1. Initialize the "iFileSize" if it is not initialized yet |
483 TInt err = DoFileSize(); |
485 TInt err = DoFileSize(); |
484 if(err != KErrNone) |
486 if(err != KErrNone) |
485 { |
487 { |
486 __FILEBUF64_INVARIANT(); |
488 __FILEBUF64_INVARIANT(); |
487 return err; |
489 return err; |
488 } |
490 } |
|
491 //2. Optimize the buffer capacity |
|
492 TInt len = aDes.MaxLength(); |
|
493 if((err = DoSetCapacity(len)) != KErrNone) |
|
494 { |
|
495 return err; |
|
496 } |
489 //3. Too big "read" request - read directly from the file |
497 //3. Too big "read" request - read directly from the file |
490 TInt len = aDes.MaxLength(); |
|
491 if(len > iCapacity) |
498 if(len > iCapacity) |
492 { |
499 { |
493 if((aFilePos + len) > iFilePos && aFilePos < (iFilePos + iLength)) |
500 if((aFilePos + len) > iFilePos && aFilePos < (iFilePos + iLength)) |
494 {//Write the pending data if the iDirty flag is set, otherwise preserve the buffer content. |
501 {//Write the pending data if the iDirty flag is set, otherwise preserve the buffer content. |
495 err = DoFileWrite1(aFilePos); |
502 err = DoFileWrite1(aFilePos); |
535 len -= ptr2.Length(); |
542 len -= ptr2.Length(); |
536 } |
543 } |
537 break; |
544 break; |
538 } |
545 } |
539 //The guessed from the previous "file read" operation file pos is correct. Start reading-ahead. |
546 //The guessed from the previous "file read" operation file pos is correct. Start reading-ahead. |
540 const TInt KMaxReadFilePosHits = 8;//The max read-ahead buffer size can be up to 2^8 times the iReadAheadSize |
547 const TInt KMaxReadFilePosHits = 4;//The max read-ahead buffer size can be up to 2^4 times the iReadAheadSize |
541 if(iNextReadFilePosHits < KMaxReadFilePosHits) |
548 if(iNextReadFilePosHits < KMaxReadFilePosHits) |
542 { |
549 { |
543 ++iNextReadFilePosHits; |
550 ++iNextReadFilePosHits; |
544 } |
551 } |
545 TInt maxReadAhead = iReadAheadSize * (1 << iNextReadFilePosHits); |
552 TInt maxReadAhead = iReadAheadSize * (1 << iNextReadFilePosHits); |
605 TInt err = DoFileSize(); |
612 TInt err = DoFileSize(); |
606 if(err != KErrNone) |
613 if(err != KErrNone) |
607 { |
614 { |
608 __FILEBUF64_INVARIANT(); |
615 __FILEBUF64_INVARIANT(); |
609 return err; |
616 return err; |
|
617 } |
|
618 if((err = DoSetCapacity(aData.Length())) != KErrNone) |
|
619 { |
|
620 return err; |
610 } |
621 } |
611 DoDiscardBufferedReadData(); |
622 DoDiscardBufferedReadData(); |
612 const TUint8* data = aData.Ptr(); |
623 const TUint8* data = aData.Ptr(); |
613 for(TInt len = aData.Length(); len > 0 && err == KErrNone;) |
624 for(TInt len = aData.Length(); len > 0 && err == KErrNone;) |
614 { |
625 { |
1076 iNextReadFilePosHits = 0; |
1087 iNextReadFilePosHits = 0; |
1077 } |
1088 } |
1078 __FILEBUF64_INVARIANT(); |
1089 __FILEBUF64_INVARIANT(); |
1079 } |
1090 } |
1080 |
1091 |
|
1092 /** |
|
1093 Sets the most appropriate buffer capacity based on the database page size. |
|
1094 The function does a lazy evaluation. The first time the function is called and |
|
1095 aRwDataLength parameter is recognized to be a database or journal page size, the new (optimal) |
|
1096 buffer capacity is calculated and set. All next DoSetCapacity() calls will detect that the new |
|
1097 capacity is already set and will return KErrNone. |
|
1098 |
|
1099 @param aRwDataLength The length of the data being read or written. |
|
1100 @return KErrNone The new capacity was set successfully, |
|
1101 KErrNoMemory Out of memory. |
|
1102 */ |
|
1103 TInt RFileBuf64::DoSetCapacity(TInt aRwDataLength) |
|
1104 { |
|
1105 const TInt KMinPageCount = 4;//the buffer capacity should be at least (KMinPageCount * page size) |
|
1106 //but not less than the original capacity. |
|
1107 const TInt KDefaultPageSize = 1024;//The journal header size is equal to 512 bytes, so it is not easy |
|
1108 //to detect the 512 bytes page size. |
|
1109 |
|
1110 __FBUF64_ASSERT(aRwDataLength > 0, EFBufPanicRwDataLength); |
|
1111 __FILEBUF64_INVARIANT(); |
|
1112 if(iOptimized) |
|
1113 { |
|
1114 __FILEBUF64_INVARIANT(); |
|
1115 return KErrNone; |
|
1116 } |
|
1117 if((aRwDataLength & (aRwDataLength - 1)) != 0 || aRwDataLength < KDefaultPageSize) |
|
1118 { |
|
1119 __FILEBUF64_INVARIANT(); |
|
1120 return KErrNone; |
|
1121 } |
|
1122 //Here: aRwDataLength is power of 2 and is bigger than the default db page size. |
|
1123 //aRwDataLength is the size of the db page. |
|
1124 const TInt pageSize = aRwDataLength; |
|
1125 TInt cnt = iCapacity / pageSize;//how many pages can fit in the buffer now |
|
1126 TInt pageCount = Max(cnt, KMinPageCount);//the number of pages that should fit in the new buffer |
|
1127 TInt newBufCapacity = pageCount * pageSize; |
|
1128 if(newBufCapacity != iCapacity) |
|
1129 { |
|
1130 TUint8* newBase = static_cast <TUint8*> (User::ReAlloc(iBase, newBufCapacity)); |
|
1131 if(!newBase) |
|
1132 { |
|
1133 __FILEBUF64_INVARIANT(); |
|
1134 return KErrNoMemory; |
|
1135 } |
|
1136 iBase = newBase; |
|
1137 iCapacity = newBufCapacity; |
|
1138 //Adjust the initial read-ahead size to be multiple of the page size. |
|
1139 if((iReadAheadSize % pageSize) != 0) |
|
1140 { |
|
1141 TInt q = iReadAheadSize / pageSize; |
|
1142 iReadAheadSize = q != 0 ? pageSize * q : pageSize; |
|
1143 } |
|
1144 } |
|
1145 iOptimized = ETrue; |
|
1146 __FILEBUF64_INVARIANT(); |
|
1147 return KErrNone; |
|
1148 } |
|
1149 |
1081 #ifdef _DEBUG |
1150 #ifdef _DEBUG |
1082 |
1151 |
1083 /** |
1152 /** |
1084 RFileBuf64 invariant. Called in _DEBUG mode at the beginning and before the end of every RFileBuf64 method |
1153 RFileBuf64 invariant. Called in _DEBUG mode at the beginning and before the end of every RFileBuf64 method |
1085 (except the init/destroy methods). |
1154 (except the init/destroy methods). |
1091 @panic FBuf64 4 In _DEBUG mode - negative iFilePos value. |
1160 @panic FBuf64 4 In _DEBUG mode - negative iFilePos value. |
1092 @panic FBuf64 5 In _DEBUG mode - set but negative iFileSize value. |
1161 @panic FBuf64 5 In _DEBUG mode - set but negative iFileSize value. |
1093 @panic FBuf64 6 In _DEBUG mode - null file handle (the RFile64 object is not created or already destroyed). |
1162 @panic FBuf64 6 In _DEBUG mode - null file handle (the RFile64 object is not created or already destroyed). |
1094 @panic FBuf64 13 In _DEBUG mode - set but negative iNextReadFilePos value. |
1163 @panic FBuf64 13 In _DEBUG mode - set but negative iNextReadFilePos value. |
1095 @panic FBuf64 14 In _DEBUG mode - negative iNextReadFilePosHits value. |
1164 @panic FBuf64 14 In _DEBUG mode - negative iNextReadFilePosHits value. |
1096 @panic FBuf64 15 In _DEBUG mode - iReadAheadSize is negative or is not power of two. |
1165 @panic FBuf64 15 In _DEBUG mode - iReadAheadSize is negative or is bigger than iCapacity. |
1097 */ |
1166 */ |
1098 void RFileBuf64::Invariant() const |
1167 void RFileBuf64::Invariant() const |
1099 { |
1168 { |
1100 __FBUF64_ASSERT(this != 0, EFBufPanicNullThis); |
1169 __FBUF64_ASSERT(this != 0, EFBufPanicNullThis); |
1101 __FBUF64_ASSERT(iCapacity > 0, EFBufPanicCapacity); |
1170 __FBUF64_ASSERT(iCapacity > 0, EFBufPanicCapacity); |
1104 __FBUF64_ASSERT(iFilePos >= 0, EFBufPanicFilePos); |
1173 __FBUF64_ASSERT(iFilePos >= 0, EFBufPanicFilePos); |
1105 __FBUF64_ASSERT(iFileSize == KFileSizeNotSet || iFileSize >= 0, EFBufPanicFileSize); |
1174 __FBUF64_ASSERT(iFileSize == KFileSizeNotSet || iFileSize >= 0, EFBufPanicFileSize); |
1106 __FBUF64_ASSERT(iFile.SubSessionHandle() != 0, EFBufPanicFileHandle); |
1175 __FBUF64_ASSERT(iFile.SubSessionHandle() != 0, EFBufPanicFileHandle); |
1107 __FBUF64_ASSERT(iNextReadFilePos == KNextReadFilePosNotSet || iNextReadFilePos >= 0, EFBufPanicNextReadFilePos); |
1176 __FBUF64_ASSERT(iNextReadFilePos == KNextReadFilePosNotSet || iNextReadFilePos >= 0, EFBufPanicNextReadFilePos); |
1108 __FBUF64_ASSERT(iNextReadFilePosHits >= 0, EFBufPanicNextReadFilePosHits); |
1177 __FBUF64_ASSERT(iNextReadFilePosHits >= 0, EFBufPanicNextReadFilePosHits); |
1109 __FBUF64_ASSERT(iReadAheadSize > 0 && (iReadAheadSize & (iReadAheadSize - 1)) == 0, EFBufPanicFileBlockSize); |
1178 __FBUF64_ASSERT(iReadAheadSize > 0, EFBufPanicFileBlockSize); |
1110 } |
1179 } |
1111 |
1180 |
1112 #endif |
1181 #endif |