persistentstorage/sql/OsLayer/os_symbian.cpp
changeset 15 3eacc0623088
parent 0 08ec8eefde2f
child 17 55f2396f6d25
--- a/persistentstorage/sql/OsLayer/os_symbian.cpp	Fri Mar 19 10:00:55 2010 +0200
+++ b/persistentstorage/sql/OsLayer/os_symbian.cpp	Fri Apr 16 16:49:27 2010 +0300
@@ -1,4 +1,4 @@
-// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 2005-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"
@@ -700,11 +700,7 @@
 	TFileName	iSysPrivDir;//"<system drive>:\" + process's private data path. Initialized in sqlite3SymbianFsOpen().
 							//Used for storing sqlite temporary files.
 	TInt64		iSeed;
-	RAllocator*	iAllocator;
 
-	enum {KZeroBufSize = SQLITE_DEFAULT_SECTOR_SIZE};
-    TBuf8<KZeroBufSize> iZeroBuf;
-	
 private:	
 	static COsLayerData* 	iOsLayerData;
 	TInt					iStoredOsErrorCode;	//Contains the last OS error code.
@@ -712,6 +708,17 @@
 	TBool					iReadOnly;			//Fh data
 	};
 
+/**
+This functon returns a reference to the current thread allocator object.
+The static RAllocator& variable will be initialized once at the moment when the function is called for 
+first time. 
+*/
+static RAllocator& Allocator()
+    {
+    static RAllocator& allocator = User::Allocator();
+    return allocator;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////       TDbFile struct declaration      /////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -819,7 +826,7 @@
 	static TInt DoGetDeviceCharacteristics(const TDriveInfo& aDriveInfo, const TVolumeIOParamInfo& aVolumeInfo);
 	static TInt DoGetSectorSize(const TDriveInfo& aDriveInfo, const TVolumeIOParamInfo& aVolumeInfo);
 	static TInt DoGetDeviceCharacteristicsAndSectorSize(TDbFile& aDbFile, TInt& aRecReadBufSize);
-	
+	static TInt DoFileSizeCorruptionCheck(TDbFile& aDbFile, const TDesC& aFname, TInt aFmode);
 	};
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1042,7 +1049,6 @@
 Initializes the COsLayerData data members with their default values.
 */
 inline COsLayerData::COsLayerData() :
-	iAllocator(0),
 	iStoredOsErrorCode(KErrNone),
 	iMessage(0),
 	iReadOnly(EFalse)
@@ -1050,7 +1056,6 @@
 	TTime now;
 	now.UniversalTime();
 	iSeed = now.Int64();
-   	iZeroBuf.FillZ(COsLayerData::KZeroBufSize);
 	}
 
 /**
@@ -1084,7 +1089,6 @@
 */
 TInt COsLayerData::DoCreate()
 	{
-	iAllocator = &User::Allocator();
 	__FS_CALL(EFsOpFsConnect, 0);
 	TInt err = iFs.Connect();
 	if(err != KErrNone)
@@ -1447,8 +1451,7 @@
 SQLite OS porting layer API.
 
 Closes the file referred by aDbFile parameter.
-If aDbFile, which is actually a pointer to a TDbFile instance, the iFullName data member is not NULL, 
-then the file will be deleted.
+If aDbFile.iFullName data member is not NULL, then the file will be deleted.
 
 @param aDbFile A pointer to a TDbFile instance, than contains the file handle to be closed.
 
@@ -1465,7 +1468,8 @@
 	__FS_CALL(EFsOpFileClose, 0);
 	dbFile.iFileBuf.Close();
 	if(dbFile.iFullName)
-		{
+		{//"iFullName" will not be NULL only when TVfs::Open() is called with SQLITE_OPEN_DELETEONCLOSE flag.
+		 //That means - SQlite expects the file to be deleted after the file close operation. 
 		__FS_CALL(EFsOpFileDelete, 0);
 		(void)COsLayerData::Instance().iFs.Delete(*dbFile.iFullName);
 		delete dbFile.iFullName;
@@ -2107,6 +2111,64 @@
 /**
 SQLite OS porting layer API.
 
+The behaviour of the RFile/RFile64::SetSize operation is not atomic for non-rugged drives. 
+When RFile/RFile64::SetSize() is called 2 operations occurs:-
+
+1)The cluster chain of the file is updated.
+2)The new file size is added to the file cache.
+
+If a power loss occurs after a SetSize there is a chance that the cluster chain was updated 
+but the new file size is not yet flushed to the file. This puts the file into an inconsistent state.
+This is most likely to occur in the journal file where the time between a SetSize and Flush can 
+be long. 
+
+For this reason this check is added when the file is opened to see if the end of the file can 
+be read straight away, if an error is returned then it is assumed that the SetSize has not be 
+completed previously. In this case the file is deleted and re-created.
+ 
+@param aDbFile A pointer to a TDbFile instance, that contains the file handle.
+@param aFname A string of 16-bit wide characters containing name of the file to be checked.
+@param aFmode The mode in which the file is opened. These mode are documented in TFileMode.
+
+@return KErrNone,          The operation has completed succesfully;
+                           Note that other system-wide error codes may also be returned.
+@see TFileMode
+@see TVfs::Open()
+@see TDbFile
+*/
+/* static */ TInt TVfs::DoFileSizeCorruptionCheck(TDbFile& aDbFile, const TDesC& aFname, TInt aFmode)
+    {
+    const TInt KMinSize = 16;
+    TInt64 size;
+    TInt err = KErrNone ;
+    TBuf8<KMinSize> buf;
+
+    err = aDbFile.iFileBuf.Size(size);
+    if (err != KErrNone)
+        {
+        return err;
+        }
+    TBool IsMinFileSize = (size >= KMinSize);
+    
+    if (IsMinFileSize)
+        {
+        err = aDbFile.iFileBuf.Read(size - KMinSize, buf);
+        }
+    
+    if (err == KErrCorrupt || err == KErrEof || !IsMinFileSize)
+        {
+        COsLayerData& osLayerData = COsLayerData::Instance();
+    
+        aDbFile.iFileBuf.Close();
+        (void) osLayerData.iFs.Delete(aFname);
+        err = aDbFile.iFileBuf.Create(osLayerData.iFs, aFname, aFmode);
+        }
+    return err;
+    }
+
+/**
+SQLite OS porting layer API.
+
 Opens or creates a file which name is in the aFileName parameter.
 If the function succeeds, the file handle and other related information will be stored in the place pointed by the 
 aDbFile parameter, a memory block of sizeof(TDbFile) size for which is allocated by the caller.
@@ -2211,6 +2273,12 @@
 				{
 				__FS_CALL(EFsOpFileOpen, 0);
 				err = dbFile.iFileBuf.Open(osLayerData.iFs, fname, fmode);
+				
+				if(err == KErrNone && ((aFlags & SQLITE_OPEN_MAIN_JOURNAL) || (aFlags & SQLITE_OPEN_TEMP_JOURNAL) || 
+                        (aFlags & SQLITE_OPEN_SUBJOURNAL) || (aFlags & SQLITE_OPEN_MASTER_JOURNAL)))
+				    {
+                    err = TVfs::DoFileSizeCorruptionCheck(dbFile, fname, fmode);
+				    }
 				}
 			if((err != KErrNone && err != KErrNoMemory && err != KErrDiskFull) && (aFlags & SQLITE_OPEN_READWRITE))
 				{
@@ -2219,7 +2287,7 @@
 				fmode &= ~EFileWrite;
 				__FS_CALL(EFsOpFileOpen, 0);
    				err = dbFile.iFileBuf.Open(osLayerData.iFs, fname, fmode);
-   				}
+				}
 			if(err != KErrNone && prevErr == KErrAccessDenied)
 				{
 				err = KErrAccessDenied;
@@ -2237,6 +2305,11 @@
 		dbFile.iFileBuf.Close();	
 		delete dbFile.iFullName;
 		dbFile.iFullName = NULL;
+        if(!aFileName && fname.Length() > 0)
+            {//temporary file, the error is not KErrNone. Then delete the file (after a successfull 
+             //temporary file creation there could be a failed memory allocation)
+            (void)osLayerData.iFs.Delete(fname);
+            }
 		}
 	else
 		{
@@ -2550,7 +2623,7 @@
 extern "C" void* sqlite3SymbianMalloc(size_t aSize)
 	{
 	__MEM_CALL(EMemOpAlloc, aSize, 0);
-	return COsLayerData::Instance().iAllocator->Alloc(aSize);
+	return Allocator().Alloc(aSize);
 	}
 
 /**
@@ -2563,10 +2636,10 @@
 extern "C" void* sqlite3SymbianRealloc(void* aPtr, size_t aSize)
 	{
 #ifdef _SQLPROFILER
-	TInt size = COsLayerData::Instance().iAllocator->AllocLen(aPtr);
+	TInt size = Allocator().AllocLen(aPtr);
 	__MEM_CALL(EMemOpRealloc, aSize, size);
 #endif
-	return COsLayerData::Instance().iAllocator->ReAlloc(aPtr, aSize);
+	return Allocator().ReAlloc(aPtr, aSize);
 	}
 
 /**
@@ -2579,10 +2652,10 @@
 extern "C" void sqlite3SymbianFree(void* aPtr)
 	{
 #ifdef _SQLPROFILER
-	TInt size = COsLayerData::Instance().iAllocator->AllocLen(aPtr);
+	TInt size = Allocator().AllocLen(aPtr);
 	__MEM_CALL(EMemOpFree, size, 0);
 #endif
-	COsLayerData::Instance().iAllocator->Free(aPtr);
+	Allocator().Free(aPtr);
 	}
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////