--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/contactsmodel/tsrc/t_IccImportLock.cpp Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,689 @@
+// Copyright (c) 2003-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:
+//
+
+
+// System includes
+#include <cntdb.h>
+#include <cntdef.h>
+#include <cntitem.h>
+#include <cntfield.h>
+#include <cntfldst.h>
+
+// System includes
+#include <e32std.h>
+#include <e32twin.h>
+#include <e32test.h>
+#include <cntdbobs.h>
+#include <e32math.h>
+
+// User includes
+#include "T_UTILS.H"
+#include "t_utils2.h"
+
+// Constant
+_LIT(KDatabaseFileName, "c:INC016848.cdb");
+
+_LIT(KSemaphoreNameOne, "One");
+_LIT(KSemaphoreNameTwo, "Two");
+
+_LIT(KThreadNameOne, "OneThread ICC");
+_LIT(KThreadNameTwo, "TwoThread Group");
+
+
+const TInt KNumberOfGroupInserts = 200;
+const TInt KNumberOfInserts = 9*KNumberOfGroupInserts/4;
+
+const TInt KStandardTimeOut = 50000;
+
+
+static RTest TheTest(_L("INC016848 - DB stressing - Group insert"));
+static RFs TheFs;
+
+//
+/* CTestActiveScheduler */
+// This class has been nicked from the t_currentdb.h / .cpp files
+class CTestActiveScheduler : public CActiveScheduler
+ {
+ public:
+ void Error (TInt aError) const;
+ };
+void CTestActiveScheduler::Error(TInt aError) const
+ {
+ User::Panic(_L("AScheduler"),aError);
+ }
+
+
+LOCAL_C void CleanupFilesL()
+ {
+ // delete the database file
+ if (CContactDatabase::ContactDatabaseExistsL(KDatabaseFileName) )
+ {
+ CContactDatabase::DeleteDatabaseL(KDatabaseFileName);
+ }
+ }
+
+
+//
+/* CConcurrentDatabaseAccessBase - Specification */
+// Forms the base class for both threads.
+class CConcurrentDatabaseAccessBase : public CBase
+ {
+ public:
+ CConcurrentDatabaseAccessBase();
+ virtual ~CConcurrentDatabaseAccessBase();
+
+ virtual void ConstructL(const TDesC& aFilename);
+
+ void RunTestL();
+
+
+ public: // data
+ RThread iThread;
+
+ protected:
+ void OpenSemaphore();
+ void CloseSemaphore();
+ void SyncronizeSignal();
+ void SyncronizeWait();
+ void OpenDatabaseL();
+ void CloseDatabase();
+ void SetUpTestL(const TDesC& aThreadName);
+ void CloseTest();
+
+ void OpenLogFileL(const TDesC& aFilename);
+ void CloseLogFile();
+
+ virtual void RunTestImplementationL() = 0;
+ void MoveWindow(TInt aDx);
+
+ protected:
+ CContactDatabase* iDb;
+ //CConsoleBase* iConsole;
+ RTest* iTest;
+ RFile iFile;
+
+
+ private:
+ RSemaphore iSemaphoreSignal;
+ RSemaphore iSemaphoreWait;
+ TBool iSemaphoreOpen;
+ HBufC* iDatabaseName;
+ CTestRegister* iFileRegister;
+ };
+
+//
+/* CConcurrentDatabaseAccessBase - Implementation */
+CConcurrentDatabaseAccessBase::CConcurrentDatabaseAccessBase()
+ {
+ }
+
+CConcurrentDatabaseAccessBase::~CConcurrentDatabaseAccessBase()
+ {
+ iThread.Close();
+ CloseSemaphore();
+ delete iDatabaseName;
+ if (iFileRegister)
+ delete iFileRegister;
+ }
+
+void CConcurrentDatabaseAccessBase::ConstructL(const TDesC& aFilename)
+ {
+ iDatabaseName = aFilename.AllocL();
+ }
+
+void CConcurrentDatabaseAccessBase::OpenDatabaseL()
+ {
+ iDb = CContactDatabase::OpenL(*iDatabaseName, CContactDatabase::EMultiThread);
+ }
+
+void CConcurrentDatabaseAccessBase::CloseDatabase()
+ {
+ delete iDb;
+ iDb = NULL;
+ }
+
+void CConcurrentDatabaseAccessBase::SetUpTestL(const TDesC& aThreadName)
+ {
+ // Set's up extra resources.
+ CConsoleBase* console = NULL;
+ TSize size;
+
+ // Create and name an RTest
+ iTest = new(ELeave) RTest(aThreadName);
+ iTest->Start(_L("Starting test"));
+
+ // Position our console window
+ size = iTest->Console()->ScreenSize();
+ size.iWidth = size.iWidth / 2 - 2;
+ size.iHeight = size.iHeight - 3;
+
+ console = Console::NewL(aThreadName, size);
+ delete const_cast<RTest*>(iTest)->Console();
+
+ iTest->SetConsole(console);
+ console->ClearScreen();
+ }
+
+void CConcurrentDatabaseAccessBase::CloseTest()
+ {
+ iTest->Close();
+ delete iTest;
+ iTest = NULL;
+ }
+
+void CConcurrentDatabaseAccessBase::OpenLogFileL(const TDesC& aFilename)
+ {
+ if (iFileRegister)
+ {
+ delete iFileRegister;
+ iFileRegister = NULL;
+ }
+ iFileRegister = CTestRegister::NewLC();
+ CleanupStack::Pop(iFileRegister);
+
+ // Open Debug File
+ iFileRegister->CreateLogFileLC(iFile, aFilename);
+ CleanupStack::Pop(&iFile);
+ }
+
+void CConcurrentDatabaseAccessBase::CloseLogFile()
+ {
+ iFile.Close();
+ delete iFileRegister;
+ iFileRegister = NULL;
+ }
+
+
+void CConcurrentDatabaseAccessBase::RunTestL()
+ {
+ // set's up an active scheduler for the thread
+ // and calls the RunTesImplementation function to actually
+ // preform the tests. This function should be implemented in the
+ // child class.
+ CTestActiveScheduler* scheduler = NULL;
+
+ scheduler = new (ELeave) CTestActiveScheduler;
+ CleanupStack::PushL(scheduler);
+ CActiveScheduler::Install(scheduler);
+
+ OpenDatabaseL();
+
+ RunTestImplementationL();
+
+ CloseDatabase();
+
+ CleanupStack::PopAndDestroy( scheduler );
+ }
+
+void CConcurrentDatabaseAccessBase::OpenSemaphore()
+ {
+ TInt success = KErrNone;
+
+ success = iSemaphoreSignal.OpenGlobal( KSemaphoreNameOne );
+ if ( success == KErrNotFound )
+ {
+ iSemaphoreSignal.CreateGlobal( KSemaphoreNameOne, 0 );
+ success = KErrNone;
+ }
+
+
+ success = iSemaphoreWait.OpenGlobal( KSemaphoreNameTwo );
+ if ( success == KErrNotFound )
+ {
+ iSemaphoreWait.CreateGlobal( KSemaphoreNameTwo, 0 );
+ }
+
+ iSemaphoreOpen = ETrue;
+ }
+
+void CConcurrentDatabaseAccessBase::CloseSemaphore()
+ {
+ if (iSemaphoreOpen)
+ {
+ iSemaphoreSignal.Close();
+ iSemaphoreWait.Close();
+ }
+
+ iSemaphoreOpen = EFalse;
+ }
+
+void CConcurrentDatabaseAccessBase::SyncronizeSignal()
+ {
+ iSemaphoreSignal.Signal();
+ iSemaphoreWait.Wait();
+ }
+
+void CConcurrentDatabaseAccessBase::SyncronizeWait()
+ {
+ iSemaphoreSignal.Wait();
+ iSemaphoreWait.Signal();
+ }
+
+
+void CConcurrentDatabaseAccessBase::MoveWindow(TInt aDx)
+ {
+ const TInt scrHgtChars=iTest->Console()->ScreenSize().iHeight;
+ TMachineInfoV1Buf machineBuf;
+ UserHal::MachineInfo(machineBuf);
+ const TMachineInfoV1& machineInfo=machineBuf();
+ const TSize scrSizePixels=machineInfo.iDisplaySizeInPixels;
+ const TInt xCentre=scrSizePixels.iWidth/2;
+ const TInt xStart=scrSizePixels.iWidth/8;
+ const TInt xEnd=3*scrSizePixels.iWidth/8;
+ const TInt xMoveBy=(xEnd-xStart)/3;
+ const TInt yCentre=scrSizePixels.iHeight/2;
+ const TInt yEnd=yCentre+scrSizePixels.iHeight/scrHgtChars;
+ TRawEvent event;
+ event.Set(TRawEvent::EButton1Down,xCentre+aDx*xStart,yCentre);
+ UserSvr::AddEvent(event);
+ event.Set(TRawEvent::EPointerMove,xCentre+aDx*(xStart+xMoveBy),yEnd);
+ UserSvr::AddEvent(event);
+ event.Set(TRawEvent::EPointerMove,xCentre+aDx*(xEnd-xMoveBy),yEnd);
+ UserSvr::AddEvent(event);
+ /*event.Set(TRawEvent::EPointerMove,xCentre+aDx*xEnd,yEnd);
+ UserSvr::AddEvent(event);*/
+ event.Set(TRawEvent::EButton1Up,xCentre+aDx*xEnd,yEnd);
+ UserSvr::AddEvent(event);
+ }
+
+
+//
+/* CConcurrentDatabaseInserter - Specification */
+// This class is the inserter thread. It's thread function should insert
+// contacts into the database using the t_utils CRandomContactGenerator class
+class CConcurrentDatabaseInserter : public CConcurrentDatabaseAccessBase
+ {
+ public:
+ CConcurrentDatabaseInserter();
+ ~CConcurrentDatabaseInserter();
+
+ static CConcurrentDatabaseInserter* NewLC(const TDesC& aFilename);
+ virtual void ConstructL(const TDesC& aFilename);
+
+ static TInt ThreadFunction(TAny* aSelf);
+
+
+ protected:
+ void RunTestImplementationL();
+
+ private:
+ };
+
+//
+/* CConcurrentDatabaseInserter - Implementation */
+
+CConcurrentDatabaseInserter* CConcurrentDatabaseInserter::NewLC(const TDesC& aFilename)
+ {
+ CConcurrentDatabaseInserter* self = NULL;
+ self = new (ELeave) CConcurrentDatabaseInserter();
+ CleanupStack::PushL( self );
+ self->ConstructL(aFilename);
+ return self;
+ }
+
+CConcurrentDatabaseInserter::CConcurrentDatabaseInserter()
+ {
+ }
+
+CConcurrentDatabaseInserter::~CConcurrentDatabaseInserter()
+ {
+ }
+
+TInt CConcurrentDatabaseInserter::ThreadFunction(TAny* aSelf)
+ {
+ CConcurrentDatabaseInserter* self = STATIC_CAST(CConcurrentDatabaseInserter*, aSelf);
+
+ // Prepare the stuff required before we start the
+ // active scheduler.
+ TInt error = KErrNone;
+ CTrapCleanup* cleanup = CTrapCleanup::New();
+ if (!cleanup)
+ return KErrNoMemory;
+
+ // Call virtual handler which does anything that needs doing as
+ // a result of the thread function from being created.
+ TRAP(error, self->RunTestL());
+
+
+ delete cleanup;
+ return error;
+ }
+
+void CConcurrentDatabaseInserter::ConstructL(const TDesC& aFilename)
+ {
+ CConcurrentDatabaseAccessBase::ConstructL(aFilename);
+
+ iThread.Create( KThreadNameOne, CConcurrentDatabaseInserter::ThreadFunction, KDefaultStackSize, 0x2000, 0x20000, this, EOwnerThread );
+ iThread.Resume();
+ iThread.SetPriority(EPriorityLess);
+ }
+
+
+void CConcurrentDatabaseInserter::RunTestImplementationL()
+ {
+ TInt retries = 0;
+ TInt counter = 0;
+ TInt errorCount = 0;
+ TInt bit = 0;
+ TInt leaveCode = KErrNone;
+ HBufC8* fileBuffer = HBufC8::NewL( 256 );
+ CleanupStack::PushL( fileBuffer );
+ TPtr8 ptr = fileBuffer->Des();
+
+ CRandomContactGenerator* generator = NULL;
+
+ SetUpTestL(KThreadNameOne());
+
+ generator = CRandomContactGenerator::NewL();
+ CleanupStack::PushL( generator );
+ generator->SetDbL(*iDb);
+ OpenLogFileL(_L("CConcurrentDatabaseInserter.txt"));
+
+ bit|= CContactDatabase::ESmsable;
+
+ OpenSemaphore();
+ SyncronizeWait(); // pause until corresponding Searcher thread is ready.
+
+ SyncronizeWait(); // Wait while other thread moves there window
+ MoveWindow(1);
+ SyncronizeWait(); // Tell other thread our window has moved
+
+ for (counter = 0; counter < KNumberOfInserts ; counter++)
+ {
+
+ retries = 0;
+
+ do
+ {
+ leaveCode = KErrNone;
+ retries++;
+ generator->AddTypicalContactForFilterL(bit, leaveCode);
+ iTest->Printf(_L("Insert contact %d Error=%d\n"), counter, leaveCode );
+ if ( leaveCode != KErrNone )
+ {
+ errorCount ++;
+ User::After( KStandardTimeOut * retries );
+ }
+ }
+ while ( leaveCode != KErrNone );
+
+ User::After( KStandardTimeOut ); // delay to allow second thread access.
+ }
+
+ iTest->Printf(_L("Insert contacts errorCount (retries) = %d\n"), errorCount );
+
+ CleanupStack::PopAndDestroy( generator );
+ CleanupStack::PopAndDestroy( fileBuffer );
+ ptr.Set(NULL, 0, 0);
+
+ iTest->Printf(_L("Finished, waiting for the other thread to stop\n"));
+ SyncronizeWait();
+ CloseSemaphore();
+ CloseLogFile();
+ CloseTest();
+ }
+
+//
+/* CConcurrentDBGroupInserter */
+class CConcurrentDBGroupInserter : public CConcurrentDatabaseAccessBase
+ {
+ public:
+ CConcurrentDBGroupInserter();
+ ~CConcurrentDBGroupInserter();
+
+ static CConcurrentDBGroupInserter* NewLC(const TDesC& aFilename);
+ virtual void ConstructL(const TDesC& aFilename);
+ static TInt ThreadFunction(TAny* aSelf);
+ static TInt FakeFunction(TAny *aParams);
+
+
+
+ protected:
+ void RunTestImplementationL();
+
+ private:
+ };
+
+CConcurrentDBGroupInserter* CConcurrentDBGroupInserter::NewLC(const TDesC& aFilename)
+ {
+ CConcurrentDBGroupInserter* self = NULL;
+ self = new (ELeave) CConcurrentDBGroupInserter();
+ CleanupStack::PushL( self );
+ self->ConstructL(aFilename);
+ return self;
+ }
+
+CConcurrentDBGroupInserter::CConcurrentDBGroupInserter()
+ {
+ }
+
+CConcurrentDBGroupInserter::~CConcurrentDBGroupInserter()
+ {
+ }
+
+TInt CConcurrentDBGroupInserter::ThreadFunction(TAny* aSelf)
+ {
+ CConcurrentDBGroupInserter* self = static_cast<CConcurrentDBGroupInserter*>(aSelf);
+
+ // Prepare the stuff required before we start the
+ // active scheduler.
+ TInt error = KErrNone;
+
+ CTrapCleanup* cleanup = CTrapCleanup::New();
+ if (!cleanup)
+ return KErrNoMemory;
+
+ // Call virtual handler which does anything that needs doing as
+ // a result of the thread function from being created.
+ TRAP(error, self->RunTestL());
+
+
+ delete cleanup;
+ return error;
+ }
+
+void CConcurrentDBGroupInserter::ConstructL(const TDesC& aFilename)
+ {
+ CConcurrentDatabaseAccessBase::ConstructL(aFilename);
+
+ iThread.Create( KThreadNameTwo, CConcurrentDBGroupInserter::ThreadFunction, KDefaultStackSize, 0x2000, 0x20000, this, EOwnerThread );
+ iThread.Resume();
+ iThread.SetPriority(EPriorityNormal);
+
+ }
+
+
+TInt CConcurrentDBGroupInserter::FakeFunction(TAny* /*aParams*/)
+ {
+ return(KErrNone);
+ }
+
+void CConcurrentDBGroupInserter::RunTestImplementationL()
+ {
+ // Prep, and get ready to run. Then before starting the search loop
+ // wait for the other thread.
+ _LIT(KGroupName, "GroupName[%d]");
+ TInt counter = 0;
+ TInt errorCount = 0;
+ TInt error = 0;
+ CContactItem* item = NULL;
+ TBuf<80> groupNameBuffer;
+
+ SetUpTestL(KThreadNameTwo());
+ OpenSemaphore();
+ SyncronizeSignal(); // wait for the other thread.
+
+ MoveWindow(-1);
+ SyncronizeSignal(); // Tell other thread our window has moved
+ SyncronizeSignal(); // Wait until other thread has moved it's window
+
+ User::After( KStandardTimeOut ); // simulate user delay,
+
+ const TInt KDelayIncrease=10000;
+ const TInt KDelayMinimum=10000;
+ const TInt KIncreaseEvery=4;
+ TInt delay=KDelayMinimum;
+ for (counter = 0; counter < KNumberOfGroupInserts; counter++)
+ {
+ User::After(delay);
+ groupNameBuffer.Format( KGroupName, counter );
+
+ FOREVER
+ {
+ // Trap the search, and display the error code on the screen
+ TRAP(error,
+ {
+ item = iDb->CreateContactGroupLC( KGroupName, /* t/f ? */ EFalse );
+ CleanupStack::PopAndDestroy( item );
+ item = NULL;
+ });
+
+ iTest->Printf(_L("Insert Group %d Error=%d\n"), counter, error );
+ if( error == KErrNone )
+ break;
+
+ errorCount ++;
+ // bail for any error other than Locked
+ if (error != KErrLocked)
+ {
+ TRAP_IGNORE(CleanupFilesL());
+ }
+ (*iTest)( error == KErrLocked );
+ }
+
+ if (counter%KIncreaseEvery==KIncreaseEvery-1)
+ delay+=KDelayIncrease;
+ }
+
+ iTest->Printf(_L("Create contact groups errorCount (retries) = %d\n"), errorCount );
+
+ iTest->Printf(_L("Finished, waiting for the other thread to stop\n"));
+
+//The errorCount counts the number of times the call to CreateContactGroupLC above returns
+//KErrLocked. On hardware it is expected that KErrLocked will occur when a write is attempted and the
+//other thread has a lock on the database. Due to the Wins threading model this should be 0 on Wins.
+//This harness can therefore be used as a benchmark on harware and the number of KErrLocked
+//contentions observed manually.
+#ifdef __WINS__
+ if (errorCount != 0)
+ {
+ TRAP_IGNORE(CleanupFilesL());
+ }
+ (*iTest)( errorCount == 0 );
+#endif
+ SyncronizeSignal();
+ CloseSemaphore();
+ CloseTest();
+ }
+
+//
+/* Test Function Prototypes */
+//
+void CreateTestDatabaseL(const TDesC& aFilename );
+void TestL();
+void doMainL();
+
+//
+/* Test Function Implementations */
+//
+void CreateTestDatabaseL(const TDesC& aFilename )
+ {
+ CContactDatabase* database = NULL;
+
+ database = CContactDatabase::ReplaceL(aFilename);
+ CleanupStack::PushL( database );
+
+ CleanupStack::PopAndDestroy( database );
+ }
+
+
+void TestL()
+ {
+ TRequestStatus groupThread;
+ TRequestStatus inserterThread;
+ CConcurrentDBGroupInserter* groupInserter = NULL;
+ CConcurrentDatabaseInserter* inserter = NULL;
+ TCntProfile profile[1];
+
+ CreateTestDatabaseL( KDatabaseFileName );
+
+ CCntTest::ProfileStart(0);
+
+ groupInserter = CConcurrentDBGroupInserter::NewLC( KDatabaseFileName );
+ inserter = CConcurrentDatabaseInserter::NewLC( KDatabaseFileName );
+
+ groupInserter->iThread.Logon(groupThread);
+ inserter->iThread.Logon(inserterThread);
+
+ User::WaitForRequest(groupThread);
+ User::WaitForRequest(inserterThread);
+
+ CCntTest::ProfileEnd(0);
+ CCntTest::ProfileResult(profile, 0, 1);
+
+ RDebug::Print(_L("Time taken (secs) %f\n"), profile[0].iTime/1000000.0);
+
+ CleanupStack::PopAndDestroy( inserter );
+ CleanupStack::PopAndDestroy( groupInserter );
+
+ }
+
+
+//
+// -------> Static global functions (source)
+//
+void doMainL()
+ {
+ User::LeaveIfError( TheFs.Connect() );
+ CleanupClosePushL(TheFs);
+
+ CTestRegister* TempFiles = CTestRegister::NewLC();
+ TempFiles->RegisterL(KDatabaseFileName, EFileTypeCnt);
+
+ // Delete any existing ini file so that we can be sure this test is ok
+ TestL();
+
+ CleanupStack::PopAndDestroy(2, &TheFs );
+
+ }
+
+/**
+
+@SYMTestCaseID PIM-T-ICCIMPORTLOCK-0001
+
+*/
+
+GLDEF_C TInt E32Main()
+ {
+ CTestActiveScheduler* scheduler = new CTestActiveScheduler;
+ CActiveScheduler::Install(scheduler);
+ CTrapCleanup* cleanupStack = NULL;
+ __UHEAP_MARK;
+ TheTest.Start(_L("@SYMTESTCaseID:PIM-T-ICCIMPORTLOCK-0001 Multi session testcode"));
+
+ TheTest.Title();
+ cleanupStack = CTrapCleanup::New();
+ TRAPD(ret, doMainL());
+ // ensure files are cleaned up even if doMainL() leaves
+ TRAP_IGNORE(CleanupFilesL() );
+ TheTest(ret == KErrNone);
+ delete cleanupStack;
+ delete scheduler;
+
+ TheTest.End();
+ TheTest.Close();
+ __UHEAP_MARKEND;
+ return(KErrNone);
+ }