--- a/loggingservices/filelogger/SSVR/FLOGSVR.CPP Tue May 25 14:35:19 2010 +0300
+++ b/loggingservices/filelogger/SSVR/FLOGSVR.CPP Wed Jun 09 11:36:09 2010 +0300
@@ -1,4 +1,4 @@
-// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 1997-2010 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
@@ -26,6 +26,11 @@
*/
const TInt KOpenLogFilesGranularity=5;
+/* Internal error. Use positive number to ensure no conflict with other error code
+ Indicate that client message has panic'ed and should not be completed.
+*/
+const TInt KErrMessagePanic = 1;
+
/**
panics for log client
@@ -268,7 +273,10 @@
{
TRAPD(ret,DispatchMessageL(aMessage));
- aMessage.Complete(ret);
+ if (ret!=KErrMessagePanic)
+ {
+ aMessage.Complete(ret);
+ }
}
void CFileLogSession::DispatchMessageL(const RMessage2& aMessage)
@@ -281,13 +289,24 @@
TLogFile log;
TPckg<TLogFile> logPckg(log);
aMessage.ReadL(0,logPckg);
- __ASSERT_ALWAYS(log.Directory().Length()!=0,aMessage.Panic(KFLoggerServerName,ELogDirectoryNameDoesNotExist));
- __ASSERT_ALWAYS(log.Name().Length()!=0,aMessage.Panic(KFLoggerServerName,ELogFileNameDoesNotExist));
+ if (log.Directory().Length()<=0)
+ {
+ aMessage.Panic(KFLoggerServerName,ELogDirectoryNameDoesNotExist);
+ User::Leave(KErrMessagePanic);
+ }
+
+ if (log.Name().Length()<=0)
+ {
+ aMessage.Panic(KFLoggerServerName,ELogFileNameDoesNotExist);
+ User::Leave(KErrMessagePanic);
+ }
// TBuf8<KLogBufferSize> buf;
TBuf8<1600> buf;
if (func==EWriteLog || func==ECreateWriteAndCloseLog)
+ {
aMessage.ReadL(1,buf);
+ }
switch (func)
{
--- a/persistentstorage/dbms/ustor/US_FILE.CPP Tue May 25 14:35:19 2010 +0300
+++ b/persistentstorage/dbms/ustor/US_FILE.CPP Wed Jun 09 11:36:09 2010 +0300
@@ -98,7 +98,7 @@
default:
__LEAVE(KErrNotSupported);
case TDbFormat::ECreate:
- store=CPermanentFileStore::CreateL(iFs,aName,EFileRead|EFileWrite);
+ store=CPermanentFileStore::CreateL(iFs,aName,EFileRead|EFileWrite);
break;
case TDbFormat::EReplace:
store=CPermanentFileStore::ReplaceL(iFs,aName,EFileRead|EFileWrite);
@@ -143,7 +143,7 @@
__ASSERT(!iName); // check construction phase
//
iName=aName.AllocL();
- const TUint mode=aMode==TDbFormat::EReadOnly ? EFileShareReadersOnly : EFileWrite;
+ TUint mode=aMode==TDbFormat::EReadOnly ? EFileShareReadersOnly : EFileWrite;
CFileStore* store=CPermanentFileStore::OpenL(iFs,*iName,mode);
iStore=store;
CDbStoreDatabase::RestoreL(DatabaseIdL(store->Root()));
--- a/persistentstorage/dbms/ustor/US_TABLE.CPP Tue May 25 14:35:19 2010 +0300
+++ b/persistentstorage/dbms/ustor/US_TABLE.CPP Wed Jun 09 11:36:09 2010 +0300
@@ -611,7 +611,9 @@
TInt size;
rec=ReadCardinality(rec,size);
size<<=2;
- if(size < 0)
+
+ //If such huge allocation is requested(KMaxTInt/2), it is highly likely the file is corrupt
+ if((size < 0) || (size >= KMaxTInt/2))
{
aRow.SetSize(0);
__LEAVE(KErrCorrupt);
--- a/persistentstorage/sql/OsLayer/FileBuf64.cpp Tue May 25 14:35:19 2010 +0300
+++ b/persistentstorage/sql/OsLayer/FileBuf64.cpp Wed Jun 09 11:36:09 2010 +0300
@@ -1107,9 +1107,9 @@
const TInt KDefaultPageSize = 1024;//The journal header size is equal to 512 bytes, so it is not easy
//to detect the 512 bytes page size.
- __FBUF64_ASSERT(aRwDataLength >= 0, EFBufPanicRwDataLength);
+ __FBUF64_ASSERT(aRwDataLength > 0, EFBufPanicRwDataLength);
__FILEBUF64_INVARIANT();
- if(iOptimized || aRwDataLength == 0)
+ if(iOptimized)
{
__FILEBUF64_INVARIANT();
return KErrNone;
--- a/persistentstorage/sql/TEST/t_sqlapi.cpp Tue May 25 14:35:19 2010 +0300
+++ b/persistentstorage/sql/TEST/t_sqlapi.cpp Wed Jun 09 11:36:09 2010 +0300
@@ -299,22 +299,24 @@
{
maxFileName = KMaxFileName -150;//The test will panic in PlatSim when the file name is too long. This line should be removed when platsim team fixes the file system defect.
}
- HBufC* dbPath = HBufC::NewLC(maxFileName);
+ HBufC* dbPath = HBufC::New(maxFileName);
+ TEST(dbPath != NULL);
+ TPtr dbPathPtr = dbPath->Des();
_LIT(KExt, ".DB");
- dbPath->Des().Copy(_L("C:"));
- dbPath->Des().Append(KSecureUid.Name());
- TInt len = maxFileName + 1 - (dbPath->Length() + KExt().Length() + privatePath.Length());
+ dbPathPtr.Copy(_L("C:"));
+ dbPathPtr.Append(KSecureUid.Name());
+ TInt len = maxFileName + 1 - (dbPathPtr.Length() + KExt().Length() + privatePath.Length());
while(--len)
{
- dbPath->Des().Append(TChar('A'));
+ dbPathPtr.Append(TChar('A'));
}
- dbPath->Des().Append(KExt);
- TEST(dbPath->Length() == (maxFileName - privatePath.Length()));
- rc = db.Create(dbPath->Des(), securityPolicy);
+ dbPathPtr.Append(KExt);
+ TEST(dbPathPtr.Length() == (maxFileName - privatePath.Length()));
+ rc = db.Create(dbPathPtr, securityPolicy);
TEST2(rc, KErrNone);
db.Close();
- rc2 = RSqlDatabase::Delete(dbPath->Des());
+ rc2 = RSqlDatabase::Delete(dbPathPtr);
TEST2(rc2, KErrNone);
// Private database with config
@@ -330,19 +332,20 @@
//Public shared database file on an existing drive (C:).
//Very long database file name.
- dbPath->Des().Copy(_L("C:\\TEST\\D"));
- len = maxFileName + 1 - (dbPath->Length() + KExt().Length());
+ dbPathPtr.Copy(_L("C:\\TEST\\D"));
+ len = maxFileName + 1 - (dbPathPtr.Length() + KExt().Length());
while(--len)
{
- dbPath->Des().Append(TChar('A'));
+ dbPathPtr.Append(TChar('A'));
}
- dbPath->Des().Append(KExt);
- TEST(dbPath->Length() == maxFileName);
- rc = db.Create(dbPath->Des());
+ dbPathPtr.Append(KExt);
+ TEST(dbPathPtr.Length() == maxFileName);
+ rc = db.Create(dbPathPtr);
db.Close();
- rc2 = RSqlDatabase::Delete(dbPath->Des());
+ rc2 = RSqlDatabase::Delete(dbPathPtr);
- CleanupStack::PopAndDestroy(dbPath);
+ delete dbPath;
+
TEST2(rc, KErrNone);
TEST2(rc2, KErrNone);
--- a/persistentstorage/sql/TEST/t_sqlfilebuf64.cpp Tue May 25 14:35:19 2010 +0300
+++ b/persistentstorage/sql/TEST/t_sqlfilebuf64.cpp Wed Jun 09 11:36:09 2010 +0300
@@ -50,6 +50,10 @@
EOomTempTest
};
+//Used in read/write OOM tests
+const TUint8 KChar = 'A';
+const TInt KPageSize = 32768;
+
///////////////////////////////////////////////////////////////////////////////////////
void DeleteTestFiles()
@@ -1118,6 +1122,140 @@
TheTest.Printf(_L("\r\n===File I/O error simulation test succeeded on iteration %d===\r\n"), cnt);
}
+/**
+@SYMTestCaseID PDS-SQL-UT-4207
+@SYMTestCaseDesc RFileBuf64::Write() OOM test.
+ The test calls RFileBuf64:Write() in an OOM
+ simulation loop and verifies that no memory is leaked.
+ The test also check that RFileBuf::DoSetCapacity() correctly operates in
+ "out of memory" situation.
+@SYMTestActions RFileBuf64::Write() OOM test.
+@SYMTestExpectedResults Test must not fail
+@SYMTestPriority High
+@SYMDEF 380056
+*/
+void WriteOomTest()
+ {
+ HBufC8* databuf = HBufC8::New(KPageSize);
+ TEST(databuf != NULL);
+ TPtr8 dataptr = databuf->Des();
+ dataptr.SetLength(KPageSize);
+ dataptr.Fill(TChar(KChar));
+
+ TInt err = KErrNoMemory;
+ TInt failingAllocationNo = 0;
+ TheTest.Printf(_L("Iteration:\r\n"));
+ while(err == KErrNoMemory)
+ {
+ TheTest.Printf(_L(" %d"), ++failingAllocationNo);
+
+ (void)TheFs.Delete(KTestFile);
+
+ MarkHandles();
+ MarkAllocatedCells();
+
+ __UHEAP_MARK;
+ __UHEAP_SETBURSTFAIL(RAllocator::EBurstFailNext, failingAllocationNo, KBurstRate);
+
+ const TInt KDefaultBufCapacity = 1024;
+ RFileBuf64 fbuf(KDefaultBufCapacity);
+ err = fbuf.Create(TheFs, KTestFile, EFileWrite | EFileRead);
+ if(err == KErrNone)
+ {
+ err = fbuf.Write(0LL, dataptr);
+ }
+ fbuf.Close();
+
+ __UHEAP_RESET;
+ __UHEAP_MARKEND;
+
+ CheckAllocatedCells();
+ CheckHandles();
+ }
+ TEST2(err, KErrNone);
+ RFile64 file;
+ err = file.Open(TheFs, KTestFile, EFileRead);
+ TEST2(err, KErrNone);
+ dataptr.Zero();
+ err = file.Read(dataptr);
+ TEST2(err, KErrNone);
+ file.Close();
+ TEST2(dataptr.Length(), KPageSize);
+ for(TInt i=0;i<KPageSize;++i)
+ {
+ TEST(dataptr[i] == KChar);
+ }
+ TheTest.Printf(_L("\r\n=== OOM Test succeeded at heap failure rate of %d ===\r\n"), failingAllocationNo);
+
+ //The file is left undeleted - to be used in ReadOomTest().
+ delete databuf;
+ }
+
+/**
+@SYMTestCaseID PDS-SQL-UT-4208
+@SYMTestCaseDesc RFileBuf64::Read() OOM test.
+ The test calls RFileBuf64:Read() in an OOM
+ simulation loop and verifies that no memory is leaked.
+ The test also check that RFileBuf::DoSetCapacity() correctly operates in
+ "out of memory" situation.
+@SYMTestActions RFileBuf64::Read() OOM test.
+@SYMTestExpectedResults Test must not fail
+@SYMTestPriority High
+@SYMDEF 380056
+*/
+void ReadOomTest()
+ {
+ HBufC8* databuf = HBufC8::New(KPageSize);
+ TEST(databuf != NULL);
+ TPtr8 dataptr = databuf->Des();
+
+ TInt err = KErrNoMemory;
+ TInt failingAllocationNo = 0;
+ TheTest.Printf(_L("Iteration:\r\n"));
+ while(err == KErrNoMemory)
+ {
+ TheTest.Printf(_L(" %d"), ++failingAllocationNo);
+
+ MarkHandles();
+ MarkAllocatedCells();
+
+ __UHEAP_MARK;
+ __UHEAP_SETBURSTFAIL(RAllocator::EBurstFailNext, failingAllocationNo, KBurstRate);
+
+ const TInt KDefaultBufCapacity = 1024;
+ RFileBuf64 fbuf(KDefaultBufCapacity);
+ err = fbuf.Open(TheFs, KTestFile, EFileRead);
+ if(err == KErrNone)
+ {
+ err = fbuf.Read(0LL, dataptr);
+ }
+ fbuf.Close();
+
+ __UHEAP_RESET;
+ __UHEAP_MARKEND;
+
+ CheckAllocatedCells();
+ CheckHandles();
+ }
+ TEST2(err, KErrNone);
+ RFile64 file;
+ err = file.Open(TheFs, KTestFile, EFileRead);
+ TEST2(err, KErrNone);
+ dataptr.Zero();
+ err = file.Read(dataptr);
+ TEST2(err, KErrNone);
+ file.Close();
+ TEST2(dataptr.Length(), KPageSize);
+ for(TInt i=0;i<KPageSize;++i)
+ {
+ TEST(dataptr[i] == KChar);
+ }
+ TheTest.Printf(_L("\r\n=== OOM Test succeeded at heap failure rate of %d ===\r\n"), failingAllocationNo);
+
+ (void)TheFs.Delete(KTestFile);
+ delete databuf;
+ }
+
void DoTests()
{
TheTest.Start(_L(" @SYMTestCaseID:PDS-SQL-UT-4132 RFileBuf64 write test 1"));
@@ -1152,6 +1290,10 @@
OomTest(EOomOpenTest);
TheTest.Next( _L(" @SYMTestCaseID:PDS-SQL-UT-4142 RFileBuf64::Temp() OOM test"));
OomTest(EOomTempTest);
+ TheTest.Next( _L(" @SYMTestCaseID:PDS-SQL-UT-4207 RFileBuf64::Write() OOM test"));
+ WriteOomTest();
+ TheTest.Next( _L(" @SYMTestCaseID:PDS-SQL-UT-4208 RFileBuf64::Read() OOM test"));
+ ReadOomTest();
TheTest.Next( _L(" @SYMTestCaseID:PDS-SQL-UT-4195 RFileBuf64::Create() file I/O error simulation test"));
CreateFileIoErrTest();
--- a/persistentstorage/store/INC/S32FILE.INL Tue May 25 14:35:19 2010 +0300
+++ b/persistentstorage/store/INC/S32FILE.INL Wed Jun 09 11:36:09 2010 +0300
@@ -290,10 +290,14 @@
@param aFs Handle to a file server session.
@param aName The full path name of the file containing the store.
@param aFileMode The mode in which the file is to be accessed. The mode is
-defined by the TFileMode type.
+defined by the TFileMode type.
@return A pointer to the new permanent file store object.
@see TFileMode */
- {return STATIC_CAST(CPermanentFileStore*,CFileStore::OpenL(aFs,aName,aFileMode,KPermanentFileStoreFactoryFunction));}
+ {
+// When the file server write caching is enabled, the order of file write operations is not guaranteed. This could cause data inconsistency in some circumstances,
+// for example, when the power is lost in the middle of a database transaction. Therefore, the file write caching is disabled for this file to maintain integrity.
+ return STATIC_CAST(CPermanentFileStore*,CFileStore::OpenL(aFs,aName,aFileMode|EFileWriteDirectIO,KPermanentFileStoreFactoryFunction));
+ }
inline CPermanentFileStore* CPermanentFileStore::OpenLC(RFs& aFs,const TDesC& aName,TUint aFileMode)
/** Opens a file containing a permanent file store, constructs a permanent file
store object, and places the pointer onto the cleanup stack.
@@ -301,10 +305,14 @@
@param aFs Handle to a file server session.
@param aName The full path name of the file containing the store.
@param aFileMode The mode in which the file is to be accessed. The mode is
-defined by the TFileMode type.
+defined by the TFileMode type.
@return A pointer to the new permanent file store object.
@see TFileMode */
- {return STATIC_CAST(CPermanentFileStore*,CFileStore::OpenLC(aFs,aName,aFileMode,KPermanentFileStoreFactoryFunction));}
+ {
+// When the file server write caching is enabled, the order of file write operations is not guaranteed. This could cause data inconsistency in some circumstances,
+// for example, when the power is lost in the middle of a database transaction. Therefore, the file write caching is disabled for this file to maintain integrity.
+ return STATIC_CAST(CPermanentFileStore*,CFileStore::OpenLC(aFs,aName,aFileMode|EFileWriteDirectIO,KPermanentFileStoreFactoryFunction));
+ }
inline CPermanentFileStore* CPermanentFileStore::CreateL(RFs& aFs,const TDesC& aName,TUint aFileMode)
/** Creates a new file and constructs a new permanent file store object to be associated
with this file.
@@ -313,10 +321,14 @@
@param aName The full path name of the new file. A file with this name must
not already exist, otherwise the function leaves.
@param aFileMode The mode in which the new file is to be accessed. This mode
-is defined by the TFileMode type.
+is defined by the TFileMode type.
@return A pointer to the new permanent file store object.
@see TFileMode */
- {return STATIC_CAST(CPermanentFileStore*,CFileStore::CreateL(aFs,aName,aFileMode,&DoNewL));}
+ {
+// When the file server write caching is enabled, the order of file write operations is not guaranteed. This could cause data inconsistency in some circumstances,
+// for example, when the power is lost in the middle of a database transaction. Therefore, the file write caching is disabled for this file to maintain integrity.
+ return STATIC_CAST(CPermanentFileStore*,CFileStore::CreateL(aFs,aName,aFileMode|EFileWriteDirectIO,&DoNewL));
+ }
inline CPermanentFileStore* CPermanentFileStore::CreateLC(RFs& aFs,const TDesC& aName,TUint aFileMode)
/** Creates a new file and constructs a new permanent file store object to be associated
with this file, and places the pointer onto the cleanup stack.
@@ -325,10 +337,14 @@
@param aName The full path name of the new file. A file with this name must
not already exist, otherwise the function leaves.
@param aFileMode The mode in which the new file is to be accessed. This mode
-is defined by the TFileMode type.
+is defined by the TFileMode type.
@return A pointer to the new permanent file store object.
@see TFileMode */
- {return STATIC_CAST(CPermanentFileStore*,CFileStore::CreateLC(aFs,aName,aFileMode,&DoNewL));}
+ {
+// When the file server write caching is enabled, the order of file write operations is not guaranteed. This could cause data inconsistency in some circumstances,
+// for example, when the power is lost in the middle of a database transaction. Therefore, the file write caching is disabled for this file to maintain integrity.
+ return STATIC_CAST(CPermanentFileStore*,CFileStore::CreateLC(aFs,aName,aFileMode|EFileWriteDirectIO,&DoNewL));
+ }
inline CPermanentFileStore* CPermanentFileStore::ReplaceL(RFs& aFs,const TDesC& aName,TUint aFileMode)
/** Creates a file, constructs a permanent file store object to be associated with
it.
@@ -338,10 +354,14 @@
@param aFs Handle to a file server session.
@param aName The full path name of the file to be replaced.
@param aFileMode The mode in which the file is to be accessed. The mode is
-defined by the TFileMode type.
+defined by the TFileMode type.
@return A pointer to the new permanent file store object.
@see TFileMode */
- {return STATIC_CAST(CPermanentFileStore*,CFileStore::ReplaceL(aFs,aName,aFileMode,&DoNewL));}
+ {
+// When the file server write caching is enabled, the order of file write operations is not guaranteed. This could cause data inconsistency in some circumstances,
+// for example, when the power is lost in the middle of a database transaction. Therefore, the file write caching is disabled for this file to maintain integrity.
+ return STATIC_CAST(CPermanentFileStore*,CFileStore::ReplaceL(aFs,aName,aFileMode|EFileWriteDirectIO,&DoNewL));
+ }
inline CPermanentFileStore* CPermanentFileStore::ReplaceLC(RFs& aFs,const TDesC& aName,TUint aFileMode)
/** Creates a file, constructs a permanent file store object to be associated with
it, and places the pointer onto the cleanup stack.
@@ -351,10 +371,14 @@
@param aFs Handle to a file server session.
@param aName The full path name of the file to be replaced.
@param aFileMode The mode in which the file is to be accessed. The mode is
-defined by the TFileMode type.
+defined by the TFileMode type.
@return A pointer to the new permanent file store object.
@see TFileMode */
- {return STATIC_CAST(CPermanentFileStore*,CFileStore::ReplaceLC(aFs,aName,aFileMode,&DoNewL));}
+ {
+// When the file server write caching is enabled, the order of file write operations is not guaranteed. This could cause data inconsistency in some circumstances,
+// for example, when the power is lost in the middle of a database transaction. Therefore, the file write caching is disabled for this file to maintain integrity.
+ return STATIC_CAST(CPermanentFileStore*,CFileStore::ReplaceLC(aFs,aName,aFileMode|EFileWriteDirectIO,&DoNewL));
+ }
inline CPermanentFileStore* CPermanentFileStore::TempL(RFs& aFs,const TDesC& aPath,TFileName& aName,TUint aFileMode)
/** Creates a temporary file and constructs a permanent file store object to be
associated with it.
@@ -372,7 +396,11 @@
defined by the TFileMode type.
@return A pointer to the new permanent file store object.
@see TFileMode */
- {return STATIC_CAST(CPermanentFileStore*,CFileStore::TempL(aFs,aPath,aName,aFileMode,&DoNewL));}
+ {
+// When the file server write caching is enabled, the order of file write operations is not guaranteed. This could cause data inconsistency in some circumstances,
+// for example, when the power is lost in the middle of a database transaction. Therefore, the file write caching is disabled for this file to maintain integrity.
+ return STATIC_CAST(CPermanentFileStore*,CFileStore::TempL(aFs,aPath,aName,aFileMode|EFileWriteDirectIO,&DoNewL));
+ }
inline CPermanentFileStore* CPermanentFileStore::TempLC(RFs& aFs,const TDesC& aPath,TFileName& aName,TUint aFileMode)
/** Creates a temporary file, constructs a permanent file store object to be associated
with it, and places the pointer onto the cleanup stack.
@@ -387,18 +415,27 @@
@param aPath The path where the new file is to be created.
@param aName On return, contains the full path name of the new file.
@param aFileMode The mode in which the file is to be accessed. The mode is
-defined by the TFileMode type.
+defined by the TFileMode type.
@return A pointer to the new permanent file store object.
@see TFileMode */
- {return STATIC_CAST(CPermanentFileStore*,CFileStore::TempLC(aFs,aPath,aName,aFileMode,&DoNewL));}
+ {
+// When the file server write caching is enabled, the order of file write operations is not guaranteed. This could cause data inconsistency in some circumstances,
+// for example, when the power is lost in the middle of a database transaction. Therefore, the file write caching is disabled for this file to maintain integrity.
+ return STATIC_CAST(CPermanentFileStore*,CFileStore::TempLC(aFs,aPath,aName,aFileMode|EFileWriteDirectIO,&DoNewL));
+ }
inline CPermanentFileStore* CPermanentFileStore::FromL(RFile& aFile)
-/** Constructs a permanent file store object from an already opened file.
+/** Constructs a permanent file store object from an already opened file. It is strongly recommended to set EFileWriteDirectIO
+bit when opening the file. This is because that when the file server write caching is enabled, the
+order of file write operations is not guaranteed. This could cause data inconsistency in some
+circumstances, for example, when the power is lost in the middle of database transaction.
+Therefore, the file write caching should be switched off to maintain integrity.
The file must already be open before calling this function.
Note that ownership of the file passes to the store. The referenced RFile
is cleared and is no longer valid.
+
@param aFile A reference to the opened file.
@return A pointer to the new permanent file store object. */
{return STATIC_CAST(CPermanentFileStore*,CFileStore::FromL(aFile,KPermanentFileStoreFactoryFunction));}
@@ -406,7 +443,11 @@
/** Constructs a permanent file store object from an already opened file, and places
the pointer onto the cleanup stack.
-The file must already be open before calling this function.
+The file must already be open before calling this function. It is strongly recommended to set EFileWriteDirectIO
+bit when opening the file. This is because that when the file server write caching is enabled, the
+order of file write operations is not guaranteed. This could cause data inconsistency in some
+circumstances, for example, when the power is lost in the middle of database transaction.
+Therefore, the file write caching should be switched off to maintain integrity.
Note that ownership of the file passes to the store. The referenced RFile
is cleared and is no longer valid.
@@ -418,7 +459,11 @@
/** Constructs a new permanent file store object in an already opened file.
The file must already be open before calling this function. The existing content
-of the file is discarded.
+of the file is discarded. It is strongly recommended to set EFileWriteDirectIO
+bit when opening the file. It is because that when file server file write cachingis on, the
+order of file writing is not guaranteed which could cause data inconsistency in some
+circumstances, for example, when the power is lost in the middle of data transaction.
+Therefore, the file write caching should be switched off to maintain the file integrity.
Note that ownership of the file passes to the store. The referenced RFile
is cleared and is no longer valid.
@@ -431,7 +476,11 @@
places the pointer onto the cleanup stack.
The file must already be open before calling this function.The existing content
-of the file is discarded.
+of the file is discarded. It is strongly recommended to set EFileWriteDirectIO
+bit when opening the file. It is because that when the file write caching in file server is on, the
+order of file writing is not guaranteed which could cause data inconsistency in some
+circumstances, for example, when the power is lost in the middle of data transaction.
+Therefore, the file file write caching should be switched off to maintain the file integrity.
Note that ownership of the file passes to the store. The referenced RFile
is cleared and is no longer valid.
--- a/persistentstorage/store/INC/S32FILEBUFSIZE.H Tue May 25 14:35:19 2010 +0300
+++ b/persistentstorage/store/INC/S32FILEBUFSIZE.H Wed Jun 09 11:36:09 2010 +0300
@@ -17,7 +17,8 @@
#define S32FILEBUFSIZE_H
#ifndef DEFAULT_FILE_BUF_SIZE
- #define DEFAULT_FILE_BUF_SIZE 4096
+ #define DEFAULT_FILE_BUF_SIZE 16384
+
#else
#if DEFAULT_FILE_BUF_SIZE < 1536
#error "DEFAULT_FILE_BUF_SIZE macro value can't be less than 1536"
--- a/persistentstorage/store/UFILE/UF_DICT.CPP Tue May 25 14:35:19 2010 +0300
+++ b/persistentstorage/store/UFILE/UF_DICT.CPP Wed Jun 09 11:36:09 2010 +0300
@@ -154,7 +154,11 @@
for (TInt wait=KLockoutLimit;;)
{
RFile file;
- TInt r=file.Open(aFs,aName,EFileShareExclusive|EFileWrite);
+ // When the file server write caching is enabled, the order of file write operations is not guaranteed.
+ // This could cause data inconsistency in some circumstances,for example, when the power is lost in the
+ // middle of a database transaction.Therefore, the file write caching is disabled for this file to maintain integrity.
+
+ TInt r=file.Open(aFs,aName,EFileShareExclusive|EFileWrite|EFileWriteDirectIO);
switch (r)
{
case KErrNone:
@@ -176,7 +180,11 @@
if (r==KErrCorrupt)
{
// silently replace the entire file if it is corrupt
- r=file.Replace(aFs,aName,EFileShareExclusive|EFileWrite);
+ // When the file server write caching is enabled, the order of file write operations is not guaranteed.
+ // This could cause data inconsistency in some circumstances,for example, when the power is lost in the
+ // middle of a database transaction.Therefore, the file write caching is disabled for this file to maintain integrity.
+
+ r=file.Replace(aFs,aName,EFileShareExclusive|EFileWrite|EFileWriteDirectIO);
if (r==KErrInUse)
break; // try again later...
if (r==KErrNone)
@@ -197,7 +205,11 @@
return;
}
case KErrNotFound:
- r=file.Create(aFs,aName,EFileShareExclusive|EFileWrite);
+ // When the file server write caching is enabled, the order of file write operations is not guaranteed.
+ // This could cause data inconsistency in some circumstances,for example, when the power is lost in the
+ // middle of a database transaction.Therefore, the file write caching is disabled for this file to maintain integrity.
+
+ r=file.Create(aFs,aName,EFileShareExclusive|EFileWrite|EFileWriteDirectIO);
if (r==KErrNone)
{
CreateStoreL(file,type);
--- a/persistentstorage/store/USTOR/UT_COLL.CPP Tue May 25 14:35:19 2010 +0300
+++ b/persistentstorage/store/USTOR/UT_COLL.CPP Wed Jun 09 11:36:09 2010 +0300
@@ -903,17 +903,54 @@
}
return ::ExtentL(Host(),iMark,Coord().Base(),aStream);
}
+
+/* relocate a stream into [iFree, aExtent)
+During compaction, for each string which is to be moved from position A1 to B1, the sequence of operations is:
+
+1. Copy stream S1 content from position A1 to position B1 . The copy never overlaps so the old stream content is still good at this point.
+2. Optionally rewrite the file header to state that stream S1 is being relocated to B1 (more about the ‘optional below’)
+3. Overwrite the TOC entry for S1 to state that the content is now at B1
+
+This function completes 3 steps above and will be called again and again for every string to be moved.
+
+In terms of data consistency, first consider the impact of a mid-write failure in any of these steps (when write caching is disabled):
+1. If step #1 only partially completes the file is good as the original content is intact and the new content was being written to otherwise free space
+2. If step #2 only partially completes the header CRC fails and only the TOC reference is considered valid (so the corrupt stream relocation record is ignored).
+ The TOC will be good because it is being overwritten with the same content.
+3. If step #3 only partially completes the entry for S1 in the TOC is corrupt, BUT the relocation record for S1 in the file header is good and will
+ override the entry in the TOC.
+
+In all cases the file is never broken by a crash in mid-compaction.
+
+Step #2 is optional – there are many cases when step #3 cannot fail ‘halfway through’ because the underlying media makes atomic block/page based
+updates and the write does not cross any block boundaries. In STORE we assume that blocks cannot be smaller than 512 bytes and any flash based
+media provides the required behavior. Thus 99% of the step #2 writes are eliminated.
+
+Note that sequencing MATTERS even for just one stream. If the TOC update hits the disk before the content is moved, and then the device fails
+we will have a broken file: S1 points to B1 which contains garbage. Equally in the case where step #2 is required (i.e. when step #3 straddles
+a block boundary and could fail) step 2 has to go before the step 3. Otherwise write #3 could go to disk and fail part way through before write #2
+and leave the TOC corrupt with no recovery in the file header.
+
+Consider the case that step 2 was omitted, so the Store relies on step 3 being completed in order to know that S1 is in location B1;
+and that no flush is done after step 3. In step 4 the stream S2 is moved – at this point the old space for stream S1 at A1 is considered empty
+– and suppose it gets moved from A2 to B2 where B2 overlaps/overwrites A1. If the writes in step 3 and step 4 are re-ordered and the step 3
+write does not happen – then the TOC will claim that S1 is still at A1 but this location in the file has been overwritten with data from S2.
+A corrupted file.
+
+Based on the knowledge above, it is strongly recommended to set EFileWriteDirectIO bit when opening the file so that the order is maintained
+when writing to the file.
+*/
void CPermanentStoreCollector::RelocateStreamL(const CPermanentStoreCollector::TEntry& aReloc, TInt aExtent)
-//
-// relocate a stream into [iFree, aExtent)
-//
+
{
if (Coord().Accessed()) // must have exclusive access to relocate the stream
__LEAVE(KErrInUse);
//
TInt end=RelocateL(aReloc.entry.ref,aReloc.len,aReloc.entry.handle == KHandleTocBase ? EFrameDescriptive16 : EFrameData16, aExtent);
+ //Step 1
Coord().RelocateL(aReloc.entry.handle, iFree);
+ // Step 2 & 3
iCoordGen=Coord().Generation(); // changed by relocation
iFree = end;
}