# HG changeset patch # User Dremov Kirill (Nokia-D-MSW/Tampere) # Date 1277131073 -10800 # Node ID 3da531bb4329b82136bd30c335576854eadd5a89 # Parent b6ab70c1385f26eb000b3a3af95e21a2b622c2fb Revision: 201025 Kit: 2010125 diff -r b6ab70c1385f -r 3da531bb4329 persistentstorage/sql/SRC/Server/Compact/SqlCompactEntry.cpp --- a/persistentstorage/sql/SRC/Server/Compact/SqlCompactEntry.cpp Wed Jun 09 11:36:09 2010 +0300 +++ b/persistentstorage/sql/SRC/Server/Compact/SqlCompactEntry.cpp Mon Jun 21 17:37:53 2010 +0300 @@ -189,6 +189,8 @@ Performs a compaction step on the database. If the number of the free pages is bigger than the number of pages removed in one compaction step, the function will reschedule itself for another compaction step. +If the database file is corrupted, then the function will remove the database entry from the timer queue - +the database won't be compacted anymore. @return KErrNoMemory, an out of memory condition has occurred; Note that the function may also return some other database specific @@ -213,8 +215,9 @@ iPageCount -= processedPageCount; __SQLASSERT(iPageCount >= 0, ESqlPanicInternalError); } - if(iPageCount <= 0) - {//No more pages to compact. Stop the compacting, move to EInactive state, remove from the timer queue. + TBool stopCompaction = err == KSqlErrCorrupt || err == KSqlErrNotDb || err == KErrCorrupt || err == KErrDisMounted; + if(iPageCount <= 0 || stopCompaction) + {//No more pages to compact or the file is corrupted . Stop the compacting, move to EInactive state, remove from the timer queue. ResetState(); iTimer.DeQueue(*this); } diff -r b6ab70c1385f -r 3da531bb4329 persistentstorage/sql/TEST/t_sqlcompact4.cpp --- a/persistentstorage/sql/TEST/t_sqlcompact4.cpp Wed Jun 09 11:36:09 2010 +0300 +++ b/persistentstorage/sql/TEST/t_sqlcompact4.cpp Mon Jun 21 17:37:53 2010 +0300 @@ -1019,6 +1019,78 @@ (void)RSqlDatabase::Delete(KDbName); } +/** +@SYMTestCaseID PDS-SQL-CT-4209 +@SYMTestCaseDesc Corrupted database background compaction test. + The test creates a database, inserts records, then deletes part of the records. + The free pages count should be big enough to kick off the background compaction. + But the database is closed immediatelly and then the db file is corrupted in a such + way that during the "database open" operation the corruption is not detected. + But the corruption is detected during the background compaction. The SQL server + should detect during the compaction that the databas eis corrupted and should + stop compacting the database (and draining the battery). Unfortunatelly, this + cannot be tested automatically, so a breakpoint should be set at the User::After() + call, and then the SQL server side should be debugged in order to berify that the + background compaction is really stopped for that database. +@SYMTestPriority High +@SYMTestActions Corrupted database background compaction test. +@SYMTestExpectedResults Test must not fail +@SYMDEF ou1cimx1#406830 +*/ +void CorruptedDbBckgCompactionTest() + { + //Step 1: Create a database with some records + const TInt KOperationCount = 100; + (void)RSqlDatabase::Delete(KDbName); + TInt err = TheDb.Create(KDbName); + TEST2(err, KErrNone); + err = TheDb.Exec(_L("BEGIN")); + TEST(err >= 0); + err = TheDb.Exec(_L("CREATE TABLE A(I INTEGER, T TEXT)")); + TEST2(err, 1); + TheText.SetLength(KTextLen); + TheText.Fill(TChar('A')); + for(TInt i=0;i<=KOperationCount;++i) + { + TheSqlTexLen.Format(_L("INSERT INTO A VALUES(%d, '%S')"), i + 1, &TheText); + err = TheDb.Exec(TheSqlTexLen); + TEST2(err, 1); + } + err = TheDb.Exec(_L("COMMIT")); + TEST(err >= 0); + //Step 2: Delete some records to free some space + err = TheDb.Exec(_L("DELETE FROM A WHERE (I % 2) = 0")); + TEST(err > 0); + //Step 3: Close the database + TheDb.Close(); + //Step 4: Corrupt the database + RFs fs; + err = fs.Connect(); + TEST2(err, KErrNone); + RFile file; + err = file.Open(fs, KDbName, EFileRead | EFileWrite); + TEST2(err, KErrNone); + TInt pos = 5000; + err = file.Seek(ESeekStart, pos); + TEST2(err, KErrNone); + TheSqlQuery.SetLength(1000); + for(TInt i=0;i<30;++i) + { + err = file.Write(TheSqlQuery); + TEST2(err, KErrNone); + } + file.Close(); + //Step 5: Check the background compaction. Wait 10 seconds allowing the SQL server to try to compact the + // database. The SQL server should detect that the SQL database is corrupted and should stop trying to + // compact the database. + err = TheDb.Open(KDbName); + TEST2(err, KErrNone); + User::After(10000000); + // + TheDb.Close(); + (void)RSqlDatabase::Delete(KDbName); + } + void DoTestsL() { CreateTestDatabase8(); @@ -1049,6 +1121,9 @@ TheTest.Next(_L(" @SYMTestCaseID:SYSLIB-SQL-UT-4071 Background compaction activated inside a DDL transaction - test")); BackgroundCompactionInDDLTransactionTest(); + + TheTest.Next(_L(" @SYMTestCaseID:PDS-SQL-CT-4209 Corrupted database background compaction test")); + CorruptedDbBckgCompactionTest(); } TInt E32Main() diff -r b6ab70c1385f -r 3da531bb4329 persistentstorage/sql/TEST/t_sqlenvdestroy.cpp --- a/persistentstorage/sql/TEST/t_sqlenvdestroy.cpp Wed Jun 09 11:36:09 2010 +0300 +++ b/persistentstorage/sql/TEST/t_sqlenvdestroy.cpp Mon Jun 21 17:37:53 2010 +0300 @@ -38,6 +38,8 @@ _LIT(KPrivateSubDir, "c:\\private\\10281e17\\cfg-TestDir.db\\"); +TParse TheParse; + /////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////// //Test macros and functions @@ -62,6 +64,53 @@ } } +void PrintDiskUsage(RFs& aFs, const TDesC& aPath, TInt aOffset = 0) + { + _LIT(KSpace, " "); + TheTest.Printf(_L("%*.*S%S\r\n"), aOffset, aOffset, &KSpace, &aPath); + TFindFile findFile(aFs); + CDir* fileNameCol = NULL; + TBuf<8> fileNameMask; + fileNameMask.Copy(_L("*.*")); + TInt err = findFile.FindWildByDir(fileNameMask, aPath, fileNameCol); + if(err == KErrNone) + { + do + { + const TDesC& file = findFile.File();//"file" variable contains the drive and the path. the file name in "file" is invalid in this case. + (void)TheParse.Set(file, NULL, NULL); + TPtrC driveName = TheParse.Drive(); + if(aPath.FindF(driveName) >= 0) + { + TInt cnt = fileNameCol->Count(); + for(TInt i=0;i path; + path.Copy(aPath); + path.Append(entry.iName); + path.Append(_L("\\")); + PrintDiskUsage(aFs, path, aOffset + 4); + } + } + } // if(aPath.FindF(driveName) >= 0) + + delete fileNameCol; + fileNameCol = NULL; + } while((err = findFile.FindWild(fileNameCol)) == KErrNone);//Get the next set of files + } + else + { + TheTest.Printf(_L(" FindWildByDir() failed with err=%d\r\n"), err); + } + } + void DoRun() { RFs fs; @@ -85,8 +134,11 @@ DoDeleteFile(fs, KDb7); DoDeleteFile(fs, KDb8); - //Create a subdir in the private datacage. The SQL production code should properly detects - //KPrivateSubDir is a directory not a database file + TheTest.Printf(_L("====================================================\r\n")); + PrintDiskUsage(fs, _L("c:\\")); + TheTest.Printf(_L("====================================================\r\n")); + + //Remove the created subdir in the private datacage. err = fs.RmDir(KPrivateSubDir); if(err != KErrNone && err != KErrNotFound) { diff -r b6ab70c1385f -r 3da531bb4329 persistentstorage/sql/TEST/testexecute/SQLite/config/Robustness.ini.DEVBOARD --- a/persistentstorage/sql/TEST/testexecute/SQLite/config/Robustness.ini.DEVBOARD Wed Jun 09 11:36:09 2010 +0300 +++ b/persistentstorage/sql/TEST/testexecute/SQLite/config/Robustness.ini.DEVBOARD Mon Jun 21 17:37:53 2010 +0300 @@ -19,7 +19,7 @@ NewBlock5=FillDisk150K NewBlock6=FillDisk100K -Exec7=Begin Transaction; +NoOperation7= // Fill the disk until an out of disk error occurs. Then close the // database because once it's reported a disk full error all bets are off.. NewBlock8=FillDisk1 @@ -33,12 +33,12 @@ // still be usable. Open11=E:\Robustness0.db -// Check the original block is still ok... -NewBlock12=CheckBlock10-1 - // Delete the data that we used to fill the disk. This is easy, our 'AddBlock' // data has 'Someint' values that are negative, the filldisk data is positive. -Exec13=Delete From Sometable where Someint >= 0; +Exec12=Delete From Sometable where Someint >= 0; + +// Check the original block is still ok... +NewBlock13=CheckBlock10-1 NewBlock14=AddBlock10-2 NewBlock15=CheckBlock10-2 diff -r b6ab70c1385f -r 3da531bb4329 persistentstorage/sql/TEST/testexecute/SQLite/config/Robustness.ini.EMULATOR --- a/persistentstorage/sql/TEST/testexecute/SQLite/config/Robustness.ini.EMULATOR Wed Jun 09 11:36:09 2010 +0300 +++ b/persistentstorage/sql/TEST/testexecute/SQLite/config/Robustness.ini.EMULATOR Mon Jun 21 17:37:53 2010 +0300 @@ -19,7 +19,7 @@ NewBlock5=FillDisk150K NewBlock6=FillDisk100K -Exec7=Begin Transaction; +NoOperation7= // Fill the disk until an out of disk error occurs. Then close the // database because once it's reported a disk full error all bets are off.. NewBlock8=FillDisk1 @@ -33,12 +33,12 @@ // still be usable. Open11=T:\Robustness0.db -// Check the original block is still ok... -NewBlock12=CheckBlock10-1 - // Delete the data that we used to fill the disk. This is easy, our 'AddBlock' // data has 'Someint' values that are negative, the filldisk data is positive. -Exec13=Delete From Sometable where Someint >= 0; +Exec12=Delete From Sometable where Someint >= 0; + +// Check the original block is still ok... +NewBlock13=CheckBlock10-1 NewBlock14=AddBlock10-2 NewBlock15=CheckBlock10-2