diff -r 000000000000 -r bde4ae8d615e os/persistentdata/persistentstorage/dbms/tdbms/t_dbthrd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/persistentdata/persistentstorage/dbms/tdbms/t_dbthrd.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,399 @@ +// Copyright (c) 1998-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 "t_dbstress.h" + +const TInt KCashLimit=500; +const TInt KOverdraftLimit=100; + +const TInt KMinHeap=0x2000; +const TInt KMaxHeap=0x20000; +#ifdef _DEBUG +const TInt KAllocFailRate=1000; +#endif + +LOCAL_D TBuf<256> Sql; +LOCAL_D TBuf8<256> LogBuf; + +class CThread : public CBase + { +public: + static TInt Entry(TAny*); +protected: + CThread() {} + ~CThread(); +private: + static void EntryL(); + void GoL(); + void ConstructL(); + void OpenViewsL(); + void RecoverL(); + void CompactL(); + void Rollback(); + void Reset(); + void WorkL(); + void TransactionL(); + void AccountL(TInt anAccount); + void StatementTimeL(); + void VerifyL(); +// + void LogSize(); +private: + RFs iFs; + RFile iLog; + CFileStore* iStore; + RDbStoreDatabase iData; + TBool iOpen; + RDbView iAccs; + RDbView iTrans; + TInt iError; + TInt iPoint; + }; + +GLDEF_C TInt StartThread(RThread& aThread,TRequestStatus& aStat) + { + TInt r=aThread.Create(_L("Thread"),CThread::Entry,KDefaultStackSize,KMinHeap,KMaxHeap,NULL); + if (r==KErrNone) + { + aThread.SetPriority(EPriorityLess); + aThread.Logon(aStat); + aThread.Resume(); + RunTimer.Start(); + } + return r; + } + +TInt CThread::Entry(TAny*) + { + CTrapCleanup* cleanup=CTrapCleanup::New(); + if (cleanup==NULL) + return KErrNoMemory; + TRAPD(r,EntryL()); + delete cleanup; + return r; + } + +void CThread::EntryL() + { + CThread* self=new(ELeave) CThread; + CleanupStack::PushL(self); + self->ConstructL(); + self->GoL(); // never returns + } + +CThread::~CThread() + {//The destructor is never ever executed! See CThread::EntryL() for details! + iAccs.Close(); + iTrans.Close(); + iData.Close(); + delete iStore; + iLog.Close(); + TInt err = iFs.Delete(KLogFile); + if(err != KErrNone) + { + RDebug::Print(_L("Error %d deleting \"%S\" file.\n"), err, &KLogFile); + } + iFs.Close(); + } + +void CThread::ConstructL() + { + User::LeaveIfError(iFs.Connect()); + User::LeaveIfError(iFs.SetSessionPath(KTestDir)); + User::LeaveIfError(iLog.Replace(iFs,KLogFile,EFileWrite|EFileStreamText)); + iStore=CFileStore::OpenL(iFs,KTestDatabase,EFileRead|EFileWrite|EFileWriteDirectIO); + LogSize(); + iData.OpenL(iStore,iStore->Root()); + } + +// +// Never exits +// +void CThread::GoL() + { + __UHEAP_SETFAIL(RHeap::ETrueRandom,KAllocFailRate); + for (;;) + { + TRAPD(r,WorkL()); + NewCount=OldCount; + LogBuf.Format(_L8(" *** Point %d with code %d"),iPoint,r); + iLog.Write(LogBuf); + LogSize(); + iError=r; + Rollback(); + LogSize(); + if (r==KErrDiskFull) + User::Leave(r); + } + } + +// +// Report the file size +// +void CThread::LogSize() + { + TInt size; + if (iStore->File().Size(size)==KErrNone) + { + LogBuf.Format(_L8("\nFile size=%d"),size); + iLog.Write(LogBuf); + } + } + +void CThread::Rollback() + { + if (iOpen) + { + iLog.Write(_L8("\nCancel")); + iAccs.Cancel(); + iTrans.Cancel(); + } + if (iData.InTransaction()) + { + iLog.Write(_L8("\nRollback")); + iData.Rollback(); + } + } + +void CThread::Reset() + { + iLog.Write(_L8("\nReset")); + TEST(iOpen); + iAccs.Reset(); + iTrans.Reset(); + } + +void CThread::RecoverL() + { + iPoint=70; + User::LeaveIfError(iLog.Write(_L8("\nRecovering"))); + if (iOpen) + { + iAccs.Close(); + iTrans.Close(); + iOpen=EFalse; + } + User::LeaveIfError(iData.Recover()); + } + +void CThread::CompactL() + { + iPoint=90; + User::LeaveIfError(iLog.Write(_L8("\nCompacting"))); + TInt b=iStore->ReclaimL(); + b-=iStore->CompactL(); + iStore->CommitL(); + LogBuf.Format(_L8(": %d bytes reclaimed"),b); + User::LeaveIfError(iLog.Write(LogBuf)); + } + +void CThread::OpenViewsL() + { + iPoint=80; + User::LeaveIfError(iLog.Write(_L8("\nOpening"))); + User::LeaveIfError(iAccs.Prepare(iData,_L("select id,balance,statement_balance from accounts"))); + TInt r=iTrans.Prepare(iData,_L("select t_date,from_id,to_id,amount from transactions")); + if (r!=KErrNone) + { + iAccs.Close(); + User::Leave(r); + } + iOpen=ETrue; + } + +void CThread::WorkL() + { + iPoint=0; + switch (iError) + { + case KErrDied: + Rollback(); + break; + case KErrNotReady: + Reset(); + break; + case KErrCorrupt: + RecoverL(); + break; + } + iPoint=1; + for (;;) + { + LogSize(); + if (!iOpen) + OpenViewsL(); + switch (Random(100)) + { + case 0: case 1: + StatementTimeL(); + break; + case 2: case 3: + RecoverL(); + break; + case 4: // case 5: case 6: case 7: case 8: case 9: + CompactL(); + break; + default: + TransactionL(); + break; + } + } + } + +void CThread::AccountL(TInt anAccount) + { + Sql.Format(_L("id=%d"),anAccount); + iAccs.FirstL(); + TEST(iAccs.FindL(iAccs.EForwards,Sql)>=0); + } + +// +// generate and add a single transaction +// +void CThread::TransactionL() + { + iPoint=2; + User::LeaveIfError(iLog.Write(_L8("\nTransaction"))); + TInt from; + if (Random(3)==0) + from=ECash; + else + from=Random(KAccountIDs); + TInt to=(Random(KAccountIDs-1)+from+1)%KAccountIDs; + AccountL(from); + iAccs.GetL(); + TEST(iAccs.ColInt(1)==from); + TInt avail=iAccs.ColInt(2)+KOverdraftLimit; + TInt amount; + if (to==ECash) + { + if (avail<10) + return; + amount=10*(1+Random(Min(avail,KCashLimit)/10)); + } + else + { + amount=1+Random(100); + if (Random(100)<5) + amount*=10; + if (Random(100)<5) + amount*=10; + while (amount>avail) + amount/=4; + if (amount==0) + return; + } + iPoint=3; + LogBuf.Format(_L8(" %08d: %d -> %d, %5d"),++TransId,from,to,amount); + User::LeaveIfError(iLog.Write(LogBuf)); + iPoint=4; + iData.Begin(); + iTrans.InsertL(); + iTrans.SetColL(1,TransId); + iTrans.SetColL(2,from); + iTrans.SetColL(3,to); + iTrans.SetColL(4,amount); + iPoint=5; + iTrans.PutL(); + iPoint=6; + iAccs.UpdateL(); // from + TInt frombalance=iAccs.ColInt(2)-amount; + iAccs.SetColL(2,frombalance); + iPoint=7; + iAccs.PutL(); + iPoint=8; + AccountL(to); + iPoint=9; + iAccs.UpdateL(); // to + TInt tobalance=iAccs.ColInt(2)+amount; + iAccs.SetColL(2,tobalance); + iPoint=10; + iAccs.PutL(); + iPoint=11; +// this will invoke commit, so update counts now + NewCount=OldCount+1; + TInt r=iData.Commit(); + if (r!=KErrNone) + { + NewCount=OldCount; + User::Leave(r); + } +// succeeded + OldCount=NewCount; + LogBuf.Format(_L8("; [%d,%d]"),frombalance,tobalance); + iLog.Write(LogBuf); + } + +// +// deliver statements +// +void CThread::StatementTimeL() + { + iPoint=50; + User::LeaveIfError(iLog.Write(_L8("\nStatement"))); + iPoint=51; + VerifyL(); + // discard transactions + iPoint=52; + iData.Begin(); + for (iTrans.BeginningL();iTrans.NextL();) + iTrans.DeleteL(); + for (iAccs.BeginningL();iAccs.NextL();) + { + iAccs.UpdateL(); + iAccs.SetColL(3,iAccs.ColInt(2)); // set statement balance + iAccs.PutL(); + } + iPoint=53; + NewCount=0; + TInt r=iData.Commit(); + if (r!=KErrNone) + { + NewCount=OldCount; + User::Leave(r); + } + OldCount=NewCount; + } + +void CThread::VerifyL() + { + TInt balance[KAccountIDs]; + TEST(iAccs.CountL()==KAccountIDs); + for (iAccs.BeginningL();iAccs.NextL();) + { + iAccs.GetL(); + TInt id=iAccs.ColInt(1); + balance[id]=iAccs.ColInt(3); + } + TInt transact=0; + for (iTrans.BeginningL();iTrans.NextL();) + { + ++transact; + iTrans.GetL(); + TInt from=iTrans.ColInt(2); + TInt to=iTrans.ColInt(3); + TInt amount=iTrans.ColInt(4); + balance[from]-=amount; + balance[to]+=amount; + } + TEST(transact==iTrans.CountL()); + for (iAccs.BeginningL();iAccs.NextL();) + { + iAccs.GetL(); + TInt id=iAccs.ColInt(1); + if (balance[id]!=iAccs.ColInt(2)) + User::Panic(_L("Oh-oh"),4321); + } + }