diff -r 000000000000 -r 08ec8eefde2f persistentstorage/dbms/tdbms/t_dbperf3.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/persistentstorage/dbms/tdbms/t_dbperf3.cpp Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,659 @@ +// Copyright (c) 2006-2009 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" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include +#include +#include +#include +#include +#include + +static RTest TheTest(_L("t_dbperf3")); +static CTrapCleanup* TheTrapCleanup; +static RFs TheFs; +static RDbs TheDbs; +static RDbNamedDatabase TheDatabase; +static RDbRowSet TheRowSet, TheRowSet2; +static RFile TheTestFile; +static TFileName TheDatabaseFileName; + +#define COUNT_OF(array) (sizeof(array)/sizeof(array[0])) + +const TInt KTrackRecordCount = 200; +const TInt KCategoryRecordCount = 50; +const TInt KStatsRecordCount = 50; +const TInt KTestBlobSize = 4096; + +//_LIT(KCreateTrackTable, "CREATE TABLE TRACKS (id INTEGER, marked_2_play INTEGER, category_id INTEGER, artist_last_name CHAR(15) NOT NULL,artist_first_name CHAR(15) NOT NULL, title CHAR(16) NOT NULL,download_site CHAR(30) NOT NULL,band_name CHAR(20) NOT NULL,origin CHAR(16),autostart INTEGER, init_volume INTEGER, music_file LONG VARCHAR)"); +_LIT(KCreateTrackIndex, "CREATE INDEX IDX1 ON TRACKS(id,marked_2_play,category_id)"); +_LIT(KCreateTrackTable, "CREATE TABLE TRACKS (id INTEGER, marked_2_play INTEGER, category_id INTEGER, artist_last_name CHAR(15) NOT NULL,artist_first_name CHAR(15) NOT NULL, title CHAR(16) NOT NULL,download_site CHAR(30) NOT NULL,band_name CHAR(20) NOT NULL,origin CHAR(16),autostart INTEGER, init_volume INTEGER)"); +_LIT(KCreateTrackTable2, "CREATE TABLE TRACKS2 (id INTEGER, music_file LONG VARCHAR)"); +//_LIT(KCreateTrackIndex2, "CREATE INDEX IDX4 ON TRACKS2(id)"); + +//_LIT(KTrackTable,"TRACKS"); + +_LIT(KId,"id"); +_LIT(KLastName,"artist_last_name"); +_LIT(KFirstName,"artist_first_name"); +_LIT(KTitle,"title"); +_LIT(KDownloadSite,"download_site"); +_LIT(KBandName,"band_name"); +_LIT(KOrigin,"origin"); +_LIT(KAutoStart,"autostart"); +_LIT(KInitVolume,"init_volume"); +_LIT(KMarked2Play,"marked_2_play"); +_LIT(KCategoryId,"category_id"); +_LIT(KMusicFile,"music_file"); + + +//category Table LITS +_LIT(KCreateCategoryTable, "CREATE TABLE CATEGORY (category_id INTEGER,category_name CHAR(20),genre INTEGER)"); +_LIT(KCreateCategoryIndex, "CREATE INDEX IDX2 ON CATEGORY(category_id)"); + +//_LIT(KCategoryTable,"CATEGORY"); + +//KCategoryId defined for category table +_LIT(KCategoryName,"category_name"); +_LIT(KGenre,"genre"); + + +//STATS Table LITS +_LIT(KCreatestatsTable, "CREATE TABLE STATS (category_id INTEGER, no_of_tracks INTEGER, no_autostart INTEGER,no_manualstart INTEGER,no_marked_2_play INTEGER, no_unmarked_2_play INTEGER, size_of_musicfiles INTEGER)"); +_LIT(KCreatestatsIndex, "CREATE UNIQUE INDEX IDX3 ON STATS(category_id)"); + +//_LIT(KStatsTable,"STATS"); + +//KCategoryId defined for category table +_LIT(KNoOfTracks,"no_of_tracks"); +_LIT(KNoMarked2Play,"no_marked_2_play"); +_LIT(KNoUnmarked2Play,"no_unmarked_2_play"); +_LIT(KNoAutostart,"no_autostart"); +_LIT(KNoManualStart,"no_manualstart"); +_LIT(KSizeOfMusicFiles,"size_of_musicfiles"); + +////////////////////////////////////////////////////// + +static TInt TheCounterFreq = -10000000; +const TInt KMicroSecIn1Sec = 1000000; + +TUint32 CalcTickDiff(TUint32 aStartTicks, TUint32 aEndTicks) + { + TInt64 diffTicks = (TInt64)aEndTicks - (TInt64)aStartTicks; + if(diffTicks < 0) + { + diffTicks = KMaxTUint32 + diffTicks + 1; + } + return (TUint32)diffTicks; + } + +//Prints aFastCount parameter (converted to us) +void PrintFcDiffAsUs(const TDesC& aFormatStr, TUint32 aFastCount) + { + double v = ((double)aFastCount * KMicroSecIn1Sec) / (double)TheCounterFreq; + TInt v2 = (TInt)v; + TheTest.Printf(aFormatStr, v2); + } + +/////////////////////////////////////////////////////////////////////////////////////// + +//Delete "aFullName" file. +static void DeleteFile(const TDesC& aFullName) + { + RFs fsSession; + TInt err = fsSession.Connect(); + if(err == KErrNone) + { + TEntry entry; + if(fsSession.Entry(aFullName, entry) == KErrNone) + { + err = fsSession.SetAtt(aFullName, 0, KEntryAttReadOnly); + if(err != KErrNone) + { + TheTest.Printf(_L("Error %d changing \"%S\" file attributes.\n"), err, &aFullName); + } + err = fsSession.Delete(aFullName); + if(err != KErrNone) + { + TheTest.Printf(_L("Error %d deleting \"%S\" file.\n"), err, &aFullName); + } + } + fsSession.Close(); + } + else + { + TheTest.Printf(_L("Error %d connecting file session. File: %S.\n"), err, &aFullName); + } + } + +/////////////////////////////////////////////////////////////////////////////////////// + +static void CloseAll() + { + TheRowSet2.Close(); + TheRowSet.Close(); + TheDatabase.Close(); + TheDbs.Close(); + TheFs.Close(); + } + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +//Tests macros and functions. +//If (!aValue) then the test will be panicked, the test data files will be deleted. +static void Check(TInt aValue, TInt aLine) + { + if(!aValue) + { + CloseAll(); + DeleteFile(TheDatabaseFileName); + TheTest(EFalse, aLine); + } + } +//If (aValue != aExpected) then the test will be panicked, the test data files will be deleted. +static void Check(TInt aValue, TInt aExpected, TInt aLine) + { + if(aValue != aExpected) + { + TheTest.Printf(_L("*** Expected error: %d, got: %d\r\n"), aExpected, aValue); + CloseAll(); + DeleteFile(TheDatabaseFileName); + TheTest(EFalse, aLine); + } + } +//Use these to test conditions. +#define TEST(arg) ::Check((arg), __LINE__) +#define TEST2(aValue, aExpected) ::Check(aValue, aExpected, __LINE__) + +/////////////////////////////////////////////////////////////////////////////////////// + +void PrintFileSize() + { + RDbDatabase::TSize s = TheDatabase.Size(); + TheTest.Printf(_L("####FileSize: %d\r\n"), s.iSize); + } + +/////////////////////////////////////////////////////////////////////////////////////// + +void FillRandomData(TDes& aData, TInt64 aSeed) + { + aData.Zero(); + for (TInt i=0; iDes()); + FillRandomData(randomData); + + RDbView view; + TInt err = view.Prepare(TheDatabase, _L("select * from TRACKS"), view.EInsertOnly); + TEST2(err, KErrNone); + TheRowSet = view; + + CDbColSet* colSet = TheRowSet.ColSetL(); + const TInt KIdIdx = colSet->ColNo(KId); + const TInt KLastNameIdx = colSet->ColNo(KLastName); + const TInt KFirstNameIdx = colSet->ColNo(KFirstName); + const TInt KTitleIdx = colSet->ColNo(KTitle); + const TInt KDownloadSiteIdx = colSet->ColNo(KDownloadSite); + const TInt KBandNameIdx = colSet->ColNo(KBandName); + const TInt KOriginIdx = colSet->ColNo(KOrigin); + const TInt KAutoStartIdx = colSet->ColNo(KAutoStart); + const TInt KInitVolumeIdx = colSet->ColNo(KInitVolume); + const TInt KMarkedToPlayIdx = colSet->ColNo(KMarked2Play); + const TInt KCategoryIdIdx = colSet->ColNo(KCategoryId); + //const TInt KMusicFileIdx = colSet->ColNo(KMusicFile); + delete colSet; + colSet = NULL; + + err = TheDatabase.Begin(); + TEST2(err, KErrNone); + + for (TInt ii=1;ii<=KTrackRecordCount;++ii) + { + TheRowSet.InsertL(); + TheRowSet.SetColL(KIdIdx, ii); + TheRowSet.SetColL(KLastNameIdx, _L("Dummy")); + TheRowSet.SetColL(KFirstNameIdx,_L("Dummy")); + TheRowSet.SetColL(KTitleIdx,_L("Dummy")); + TheRowSet.SetColL(KDownloadSiteIdx,_L("Dummy")); + TheRowSet.SetColL(KBandNameIdx,_L("Dummy")); + TheRowSet.SetColL(KOriginIdx,_L("Dummy")); + TheRowSet.SetColL(KAutoStartIdx,(ii%2)); + TheRowSet.SetColL(KInitVolumeIdx,(ii%2)); + TheRowSet.SetColL(KMarkedToPlayIdx,(ii%2)); + TheRowSet.SetColL(KCategoryIdIdx,(ii%KCategoryRecordCount)); + + //RDbColWriteStream musicfile; + //musicfile.OpenLC(TheRowSet, KMusicFileIdx); + //musicfile.WriteL(randomData,KTestBlobSize); + //musicfile.CommitL(); + //CleanupStack::PopAndDestroy(&musicfile); + + TheRowSet.PutL(); + } + + err = TheDatabase.Commit(); + TEST2(err, KErrNone); + + //err = TheDatabase.Compact(); + //TEST2(err, KErrNone); + + TheRowSet.Close(); + + //////////////////////////////////////////////////////////////////////////////////////////////// + + err = view.Prepare(TheDatabase, _L("select * from TRACKS2"), view.EInsertOnly); + TEST2(err, KErrNone); + TheRowSet = view; + + colSet = TheRowSet.ColSetL(); + const TInt KIdIdx2 = colSet->ColNo(KId); + const TInt KMusicFileIdx2 = colSet->ColNo(KMusicFile); + delete colSet; + + err = TheDatabase.Begin(); + TEST2(err, KErrNone); + + for (TInt ii=1;ii<=KTrackRecordCount;++ii) + { + TheRowSet.InsertL(); + TheRowSet.SetColL(KIdIdx2, ii); + + RDbColWriteStream musicfile; + musicfile.OpenLC(TheRowSet, KMusicFileIdx2); + musicfile.WriteL(randomData,KTestBlobSize); + musicfile.CommitL(); + CleanupStack::PopAndDestroy(&musicfile); + + TheRowSet.PutL(); + } + + err = TheDatabase.Commit(); + TEST2(err, KErrNone); + + //err = TheDatabase.Compact(); + //TEST2(err, KErrNone); + + TheRowSet.Close(); + + CleanupStack::PopAndDestroy(randomDataBuf); + } + +void InsertCategoryTableL() + { + RDbView view; + TInt err = view.Prepare(TheDatabase, _L("select * from CATEGORY"), view.EInsertOnly); + TEST2(err, KErrNone); + TheRowSet = view; + + CDbColSet* colSet = TheRowSet.ColSetL(); + const TInt KCategoryIdIdx = colSet->ColNo(KCategoryId); + const TInt KCategoryNameIdx = colSet->ColNo(KCategoryName); + const TInt KGenreIdx = colSet->ColNo(KGenre); + delete colSet; + + err = TheDatabase.Begin(); + TEST2(err, KErrNone); + + for (TInt ii=1;ii<=KCategoryRecordCount;++ii) + { + TheRowSet.InsertL(); + TheRowSet.SetColL(KCategoryIdIdx, ii); + TheRowSet.SetColL(KCategoryNameIdx, _L("History")); + TheRowSet.SetColL(KGenreIdx,(ii*500)); + TheRowSet.PutL(); + } + + err = TheDatabase.Commit(); + TEST2(err, KErrNone); + + //err = TheDatabase.Compact(); + //TEST2(err, KErrNone); + + TheRowSet.Close(); + } + +void InsertStatsTableL() + { + RDbView view; + TInt err = view.Prepare(TheDatabase, _L("select * from STATS"), view.EInsertOnly); + TEST2(err, KErrNone); + TheRowSet = view; + + CDbColSet* colSet = TheRowSet.ColSetL(); + const TInt KCategoryIdIdx = colSet->ColNo(KCategoryId); + const TInt KTrackCntIdx = colSet->ColNo(KNoOfTracks); + const TInt KMarkedToPlayCntIdx = colSet->ColNo(KNoMarked2Play); + const TInt KUnmarkedToPlayCntIdx = colSet->ColNo(KNoUnmarked2Play); + const TInt KAutoStartCntIdx = colSet->ColNo(KNoAutostart); + const TInt KManualStartCntIdx = colSet->ColNo(KNoManualStart); + const TInt KSizeMusicFilesIdx = colSet->ColNo(KSizeOfMusicFiles); + delete colSet; + + TInt default_Stat = 0; + + err = TheDatabase.Begin(); + TEST2(err, KErrNone); + + for (TInt ii=0;ii& aTracks) + { + TUint32 fc = User::FastCounter(); + RDbView view; + TUint32 fc2 = User::FastCounter(); + TInt err = view.Prepare(TheDatabase, _L("select id from TRACKS"), view.EReadOnly); + TEST2(err, KErrNone); + PrintFcDiffAsUs(_L("###\"Prepare()\",time=%d us\r\n"), CalcTickDiff(fc2, User::FastCounter())); + fc2 = User::FastCounter(); + err = view.EvaluateAll(); + TEST2(err, KErrNone); + PrintFcDiffAsUs(_L("###\"EvaluateAll()\",time=%d us\r\n"), CalcTickDiff(fc2, User::FastCounter())); + TheRowSet = view; + + TUint32 diff1 = 0, diff2 = 0; + TInt count = 0; + while(count < aCount) + { + fc2 = User::FastCounter(); + if(!TheRowSet.NextL()) + { + break; + } + diff1 += CalcTickDiff(fc2, User::FastCounter()); + fc2 = User::FastCounter(); + TheRowSet.GetL(); + diff2 += CalcTickDiff(fc2, User::FastCounter()); + aTracks.Append(TheRowSet.ColInt(1)); + ++count; + } + TEST2(count, aCount); + PrintFcDiffAsUs(_L("###\"Total NextL()\",time=%d us\r\n"), diff1); + PrintFcDiffAsUs(_L("###\"Total GetL()\",time=%d us\r\n"), diff2); + + fc2 = User::FastCounter(); + TheRowSet.Close(); + PrintFcDiffAsUs(_L("###\"Close()\",time=%d us\r\n"), CalcTickDiff(fc2, User::FastCounter())); + PrintFcDiffAsUs(_L("###\"SELECT FROM TRACKS\",time=%d us\r\n"), CalcTickDiff(fc, User::FastCounter())); + } + +/** +@SYMTestCaseID PDS-DBMS-UT-4009 +@SYMTestCaseDesc DBMS performance tests. +@SYMTestPriority High +@SYMTestActions The test opens the test database and: + - selects the ids of the tracks to be deleted and collects them into an array; + - deletes the recods with matching track ids from TRACK table; + - deletes the recods with matching track ids from TRACK2 table; + The execution times are printed out. +@SYMTestExpectedResults Test must not fail +@SYMREQ REQ7141 +*/ +void DeleteTracksL() + { + TheTest.Printf(_L("Record count: %d\r\n"), KTrackRecordCount); + + RArray tracks; + tracks.ReserveL(KTrackRecordCount); + CleanupClosePushL(tracks); + SelectTracksL(KTrackRecordCount, tracks); + // + _LIT(KDeleteSql, "DELETE FROM tracks WHERE id>=%d AND id<=%d"); + + TBuf<100> sql; + sql.Format(KDeleteSql, tracks[0], tracks[tracks.Count() - 1]); + + TUint32 fc2 = User::FastCounter(); + + TInt err = TheDatabase.Begin(); + TEST2(err, KErrNone); + + TUint32 fc = User::FastCounter(); + TInt rc = TheDatabase.Execute(sql); + PrintFcDiffAsUs(_L("###\"DELETE FROM TRACKS\",time=%d us\r\n"), CalcTickDiff(fc, User::FastCounter())); + TEST2(rc, KTrackRecordCount); + TheTest.Printf(_L("Deleted record count: %d\r\n"), rc); + + sql.Replace(12, 6, _L("TRACKS2")); + fc = User::FastCounter(); + rc = TheDatabase.Execute(sql); + PrintFcDiffAsUs(_L("###\"DELETE FROM TRACKS2\",time=%d us\r\n"), CalcTickDiff(fc, User::FastCounter())); + TEST2(rc, KTrackRecordCount); + TheTest.Printf(_L("Deleted record count: %d\r\n"), rc); + + err = TheDatabase.Commit(); + TEST2(err, KErrNone); + + PrintFcDiffAsUs(_L("###Total \"DELETE FROM TRACKS\",time=%d us\r\n"), CalcTickDiff(fc2, User::FastCounter())); + + CleanupStack::PopAndDestroy(&tracks); + } + +/////////////////////////////////////////////////////////////////////////////////////// + +//This test checks how RDbDatabase::Commit() works if there are some active RDbRowSet objects - +//read-only and updatable. The expectation is that the Commit() call won't fail, the RDbRowSet objects +//retain their pre-commit positions. +void CommitTestL() + { + //Create 2 test tables, insert some records in the first table + TheDatabase.Close(); + TInt err = TheDatabase.Replace(TheFs, TheDatabaseFileName); + TEST2(err, KErrNone); + err = TheDatabase.Execute(_L("CREATE TABLE AA1(Id INTEGER)")); + TEST2(err, KErrNone); + err = TheDatabase.Execute(_L("CREATE TABLE AA2(Id INTEGER)")); + TEST2(err, KErrNone); + err = TheDatabase.Execute(_L("INSERT INTO AA1(Id) VALUES(1)")); + TEST2(err, 1); + err = TheDatabase.Execute(_L("INSERT INTO AA1(Id) VALUES(2)")); + TEST2(err, 1); + err = TheDatabase.Execute(_L("INSERT INTO AA1(Id) VALUES(3)")); + TEST2(err, 1); + //Begin transaction + err = TheDatabase.Begin(); + TEST2(err, KErrNone); + //Prepare read-only view and call FirstL() (TheRowSet object) + RDbView view; + err = view.Prepare(TheDatabase, _L("select * from AA1"), RDbRowSet::EReadOnly); + TEST2(err, KErrNone); + TheRowSet = view; + err = view.EvaluateAll(); //DBMS can use FirstL() without the EvaluateAll() call in this case + TEST2(err, KErrNone); + TBool rc = TheRowSet.FirstL(); + TEST(rc); + //Prepare updatable view and call NextL() (TheRowSet2 object) + err = view.Prepare(TheDatabase, _L("select * from AA1"), RDbRowSet::EUpdatable); + TEST2(err, KErrNone); + TheRowSet2 = view; + err = view.EvaluateAll(); //DBMS can use NextL() without the EvaluateAll() call in this case + TEST2(err, KErrNone); + rc = TheRowSet2.FirstL(); + TEST(rc); + rc = TheRowSet2.NextL(); + TEST(rc); + //Execute one INSERT statement + err = TheDatabase.Execute(_L("INSERT INTO AA2(Id) VALUES(1)")); + TEST2(err, 1); + //Commit transaction + err = TheDatabase.Commit(); + TEST2(err, KErrNone); + //Check the retrieved by TheRowSet record + TheRowSet.GetL(); + TEST2(TheRowSet.ColInt(1), 1); + //Check the retrieved by TheRowSet2 record + TheRowSet2.GetL(); + TEST2(TheRowSet2.ColInt(1), 2); + //Cleanup + TheRowSet2.Close(); + TheRowSet.Close(); + TheDatabase.Close(); + } + +/////////////////////////////////////////////////////////////////////////////////////// + +void DoTestL() + { + TheTest.Start(_L("Get fast counter frequency")); + GetFastCounterFrequency(); + + TheTest.Next(_L("Create&Fill test database")); + CreateDatabase(); + FillDatabaseL(); + + TheTest.Next(_L(" @SYMTestCaseID:PDS-DBMS-UT-4009 Delete tracks")); + DeleteTracksL(); + + TheTest.Next(_L("Commit() test (not a performance test)")); + CommitTestL(); + } + +/////////////////////////////////////////////////////////////////////////////////////// + +//Usage: "t_dbperf3 [:]" +TInt E32Main() + { + TheTest.Title(); + + TheTrapCleanup = CTrapCleanup::New(); + TEST(TheTrapCleanup != NULL); + + //Construct test database file name + _LIT(KTestDatabase, "c:\\dbms-tst\\t_dbperf3.db"); + TFileName fname; + User::CommandLine(fname); + TParse parse; + parse.Set(fname, &KTestDatabase, 0); + const TDesC& dbFilePath = parse.FullName(); + TheDatabaseFileName.Copy(dbFilePath); + TheTest.Printf(_L("Test database: %S\r\n"), &TheDatabaseFileName); + + __UHEAP_MARK; + + TInt err = TheFs.Connect(); + TEST2(err, KErrNone); + err = TheFs.MkDir(TheDatabaseFileName); + TheTest.Printf(_L("MkDir(): err=%d\r\n"), err); + TEST(err == KErrNone || err == KErrAlreadyExists); + + DeleteFile(TheDatabaseFileName); + + TRAP(err, DoTestL()); + TEST2(err, KErrNone); + + CloseAll(); + DeleteFile(TheDatabaseFileName); + + __UHEAP_MARKEND; + + TheTest.End(); + TheTest.Close(); + + delete TheTrapCleanup; + return KErrNone; + }