persistentstorage/dbms/tdbms/t_dbthrd.cpp
changeset 0 08ec8eefde2f
child 6 5ffdb8f2067f
equal deleted inserted replaced
-1:000000000000 0:08ec8eefde2f
       
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include "t_dbstress.h"
       
    17 
       
    18 const TInt KCashLimit=500;
       
    19 const TInt KOverdraftLimit=100;
       
    20 
       
    21 const TInt KMinHeap=0x2000;
       
    22 const TInt KMaxHeap=0x20000;
       
    23 #ifdef _DEBUG
       
    24 const TInt KAllocFailRate=1000;
       
    25 #endif
       
    26 
       
    27 LOCAL_D TBuf<256> Sql;
       
    28 LOCAL_D	TBuf8<256> LogBuf;
       
    29 
       
    30 class CThread : public CBase
       
    31 	{
       
    32 public:
       
    33 	static TInt Entry(TAny*);
       
    34 protected:
       
    35 	CThread() {}
       
    36 	~CThread();
       
    37 private:
       
    38 	static void EntryL();
       
    39 	void GoL();
       
    40 	void ConstructL();
       
    41 	void OpenViewsL();
       
    42 	void RecoverL();
       
    43 	void CompactL();
       
    44 	void Rollback();
       
    45 	void Reset();
       
    46 	void WorkL();
       
    47 	void TransactionL();
       
    48 	void AccountL(TInt anAccount);
       
    49 	void StatementTimeL();
       
    50 	void VerifyL();
       
    51 //
       
    52 	void LogSize();
       
    53 private:
       
    54 	RFs iFs;
       
    55 	RFile iLog;
       
    56 	CFileStore* iStore;
       
    57 	RDbStoreDatabase iData;
       
    58 	TBool iOpen;
       
    59 	RDbView iAccs;
       
    60 	RDbView iTrans;
       
    61 	TInt iError;
       
    62 	TInt iPoint;
       
    63 	};
       
    64 
       
    65 GLDEF_C TInt StartThread(RThread& aThread,TRequestStatus& aStat)
       
    66 	{
       
    67 	TInt r=aThread.Create(_L("Thread"),CThread::Entry,KDefaultStackSize,KMinHeap,KMaxHeap,NULL);
       
    68 	if (r==KErrNone)
       
    69 		{
       
    70 		aThread.SetPriority(EPriorityLess);
       
    71 		aThread.Logon(aStat);
       
    72 		aThread.Resume();
       
    73 		RunTimer.Start();
       
    74 		}
       
    75 	return r;
       
    76 	}
       
    77 
       
    78 TInt CThread::Entry(TAny*)
       
    79 	{
       
    80 	CTrapCleanup* cleanup=CTrapCleanup::New();
       
    81 	if (cleanup==NULL)
       
    82 		return KErrNoMemory;
       
    83 	TRAPD(r,EntryL());
       
    84 	delete cleanup;
       
    85 	return r;
       
    86 	}
       
    87 
       
    88 void CThread::EntryL()
       
    89 	{
       
    90 	CThread* self=new(ELeave) CThread;
       
    91 	CleanupStack::PushL(self);
       
    92 	self->ConstructL();
       
    93 	self->GoL();		// never returns
       
    94 	}
       
    95 
       
    96 CThread::~CThread()
       
    97 	{//The destructor is never ever executed! See CThread::EntryL() for details!
       
    98 	iAccs.Close();
       
    99 	iTrans.Close();
       
   100 	iData.Close();
       
   101 	delete iStore;
       
   102 	iLog.Close();
       
   103 	TInt err = iFs.Delete(KLogFile);
       
   104 	if(err != KErrNone)
       
   105 		{
       
   106 		RDebug::Print(_L("Error %d deleting \"%S\" file.\n"), err, &KLogFile);
       
   107 		}
       
   108 	iFs.Close();
       
   109 	}
       
   110 
       
   111 void CThread::ConstructL()
       
   112 	{
       
   113 	User::LeaveIfError(iFs.Connect());
       
   114 	User::LeaveIfError(iFs.SetSessionPath(KTestDir));
       
   115 	User::LeaveIfError(iLog.Replace(iFs,KLogFile,EFileWrite|EFileStreamText));
       
   116 	iStore=CFileStore::OpenL(iFs,KTestDatabase,EFileRead|EFileWrite);
       
   117 	LogSize();
       
   118 	iData.OpenL(iStore,iStore->Root());
       
   119 	}
       
   120 
       
   121 //
       
   122 // Never exits
       
   123 //
       
   124 void CThread::GoL()
       
   125 	{
       
   126 	__UHEAP_SETFAIL(RHeap::ETrueRandom,KAllocFailRate);
       
   127 	for (;;)
       
   128 		{
       
   129 		TRAPD(r,WorkL());
       
   130 		NewCount=OldCount;
       
   131 		LogBuf.Format(_L8(" *** Point %d with code %d"),iPoint,r);
       
   132 		iLog.Write(LogBuf);
       
   133 		LogSize();
       
   134 		iError=r;
       
   135 		Rollback();
       
   136 		LogSize();
       
   137 		if (r==KErrDiskFull)
       
   138 			User::Leave(r);
       
   139 		}
       
   140 	}
       
   141 
       
   142 //
       
   143 // Report the file size
       
   144 //
       
   145 void CThread::LogSize()
       
   146 	{
       
   147 	TInt size;
       
   148 	if (iStore->File().Size(size)==KErrNone)
       
   149 		{
       
   150 		LogBuf.Format(_L8("\nFile size=%d"),size);
       
   151 		iLog.Write(LogBuf);
       
   152 		}
       
   153 	}
       
   154 
       
   155 void CThread::Rollback()
       
   156 	{
       
   157 	if (iOpen)
       
   158 		{
       
   159 		iLog.Write(_L8("\nCancel"));
       
   160 		iAccs.Cancel();
       
   161 		iTrans.Cancel();
       
   162 		}
       
   163 	if (iData.InTransaction())
       
   164 		{
       
   165 		iLog.Write(_L8("\nRollback"));
       
   166 		iData.Rollback();
       
   167 		}
       
   168 	}
       
   169 
       
   170 void CThread::Reset()
       
   171 	{
       
   172 	iLog.Write(_L8("\nReset"));
       
   173 	test(iOpen);
       
   174 	iAccs.Reset();
       
   175 	iTrans.Reset();
       
   176 	}
       
   177 
       
   178 void CThread::RecoverL()
       
   179 	{
       
   180 	iPoint=70;
       
   181 	User::LeaveIfError(iLog.Write(_L8("\nRecovering")));
       
   182 	if (iOpen)
       
   183 		{
       
   184 		iAccs.Close();
       
   185 		iTrans.Close();
       
   186 		iOpen=EFalse;
       
   187 		}
       
   188 	User::LeaveIfError(iData.Recover());
       
   189 	}
       
   190 
       
   191 void CThread::CompactL()
       
   192 	{
       
   193 	iPoint=90;
       
   194 	User::LeaveIfError(iLog.Write(_L8("\nCompacting")));
       
   195 	TInt b=iStore->ReclaimL();
       
   196 	b-=iStore->CompactL();
       
   197 	iStore->CommitL();
       
   198 	LogBuf.Format(_L8(": %d bytes reclaimed"),b);
       
   199 	User::LeaveIfError(iLog.Write(LogBuf));
       
   200 	}
       
   201 
       
   202 void CThread::OpenViewsL()
       
   203 	{
       
   204 	iPoint=80;
       
   205 	User::LeaveIfError(iLog.Write(_L8("\nOpening")));
       
   206 	User::LeaveIfError(iAccs.Prepare(iData,_L("select id,balance,statement_balance from accounts")));
       
   207 	TInt r=iTrans.Prepare(iData,_L("select t_date,from_id,to_id,amount from transactions"));
       
   208 	if (r!=KErrNone)
       
   209 		{
       
   210 		iAccs.Close();
       
   211 		User::Leave(r);
       
   212 		}
       
   213 	iOpen=ETrue;
       
   214 	}
       
   215 
       
   216 void CThread::WorkL()
       
   217 	{
       
   218 	iPoint=0;
       
   219 	switch (iError)
       
   220 		{
       
   221 	case KErrDied:
       
   222 		Rollback();
       
   223 		break;
       
   224 	case KErrNotReady:
       
   225 		Reset();
       
   226 		break;
       
   227 	case KErrCorrupt:
       
   228 		RecoverL();
       
   229 		break;
       
   230 		}
       
   231 	iPoint=1;
       
   232 	for (;;)
       
   233 		{
       
   234 		LogSize();
       
   235 		if (!iOpen)
       
   236 			OpenViewsL();
       
   237 		switch (Random(100))
       
   238 			{
       
   239 		case 0:	case 1:
       
   240 			StatementTimeL();
       
   241 			break;
       
   242 		case 2: case 3:
       
   243 			RecoverL();
       
   244 			break;
       
   245 		case 4: // case 5: case 6: case 7: case 8: case 9:
       
   246 			CompactL();
       
   247 			break;
       
   248 		default:
       
   249 			TransactionL();
       
   250 			break;
       
   251 			}
       
   252 		}
       
   253 	}
       
   254 
       
   255 void CThread::AccountL(TInt anAccount)
       
   256 	{
       
   257 	Sql.Format(_L("id=%d"),anAccount);
       
   258 	iAccs.FirstL();
       
   259 	test(iAccs.FindL(iAccs.EForwards,Sql)>=0);
       
   260 	}
       
   261 
       
   262 //
       
   263 // generate and add a single transaction
       
   264 //
       
   265 void CThread::TransactionL()
       
   266 	{
       
   267 	iPoint=2;
       
   268 	User::LeaveIfError(iLog.Write(_L8("\nTransaction")));
       
   269 	TInt from;
       
   270 	if (Random(3)==0)
       
   271 		from=ECash;
       
   272 	else
       
   273 		from=Random(KAccountIDs);
       
   274 	TInt to=(Random(KAccountIDs-1)+from+1)%KAccountIDs;
       
   275 	AccountL(from);
       
   276 	iAccs.GetL();
       
   277 	test(iAccs.ColInt(1)==from);
       
   278 	TInt avail=iAccs.ColInt(2)+KOverdraftLimit;
       
   279 	TInt amount;
       
   280 	if (to==ECash)
       
   281 		{
       
   282 		if (avail<10)
       
   283 			return;
       
   284 		amount=10*(1+Random(Min(avail,KCashLimit)/10));
       
   285 		}
       
   286 	else
       
   287 		{
       
   288 		amount=1+Random(100);
       
   289 		if (Random(100)<5)
       
   290 			amount*=10;
       
   291 		if (Random(100)<5)
       
   292 			amount*=10;
       
   293 		while (amount>avail)
       
   294 			amount/=4;
       
   295 		if (amount==0)
       
   296 			return;
       
   297 		}
       
   298 	iPoint=3;
       
   299 	LogBuf.Format(_L8(" %08d: %d -> %d, %5d"),++TransId,from,to,amount);
       
   300 	User::LeaveIfError(iLog.Write(LogBuf));
       
   301 	iPoint=4;
       
   302 	iData.Begin();
       
   303 	iTrans.InsertL();
       
   304 	iTrans.SetColL(1,TransId);
       
   305 	iTrans.SetColL(2,from);
       
   306 	iTrans.SetColL(3,to);
       
   307 	iTrans.SetColL(4,amount);
       
   308 	iPoint=5;
       
   309 	iTrans.PutL();
       
   310 	iPoint=6;
       
   311 	iAccs.UpdateL();	// from
       
   312 	TInt frombalance=iAccs.ColInt(2)-amount;
       
   313 	iAccs.SetColL(2,frombalance);
       
   314 	iPoint=7;
       
   315 	iAccs.PutL();
       
   316 	iPoint=8;
       
   317 	AccountL(to);
       
   318 	iPoint=9;
       
   319 	iAccs.UpdateL();	// to
       
   320 	TInt tobalance=iAccs.ColInt(2)+amount;
       
   321 	iAccs.SetColL(2,tobalance);
       
   322 	iPoint=10;
       
   323 	iAccs.PutL();
       
   324 	iPoint=11;
       
   325 // this will invoke commit, so update counts now
       
   326 	NewCount=OldCount+1;
       
   327 	TInt r=iData.Commit();
       
   328 	if (r!=KErrNone)
       
   329 		{
       
   330 		NewCount=OldCount;
       
   331 		User::Leave(r);
       
   332 		}
       
   333 // succeeded
       
   334 	OldCount=NewCount;
       
   335 	LogBuf.Format(_L8("; [%d,%d]"),frombalance,tobalance);
       
   336 	iLog.Write(LogBuf);
       
   337 	}
       
   338 
       
   339 //
       
   340 // deliver statements
       
   341 //
       
   342 void CThread::StatementTimeL()
       
   343 	{
       
   344 	iPoint=50;
       
   345 	User::LeaveIfError(iLog.Write(_L8("\nStatement")));
       
   346 	iPoint=51;
       
   347 	VerifyL();
       
   348 	// discard transactions
       
   349 	iPoint=52;
       
   350 	iData.Begin();
       
   351 	for (iTrans.BeginningL();iTrans.NextL();)
       
   352 		iTrans.DeleteL();
       
   353 	for (iAccs.BeginningL();iAccs.NextL();)
       
   354 		{
       
   355 		iAccs.UpdateL();
       
   356 		iAccs.SetColL(3,iAccs.ColInt(2));	// set statement balance
       
   357 		iAccs.PutL();
       
   358 		}
       
   359 	iPoint=53;
       
   360 	NewCount=0;
       
   361 	TInt r=iData.Commit();
       
   362 	if (r!=KErrNone)
       
   363 		{
       
   364 		NewCount=OldCount;
       
   365 		User::Leave(r);
       
   366 		}
       
   367 	OldCount=NewCount;
       
   368 	}
       
   369 
       
   370 void CThread::VerifyL()
       
   371 	{
       
   372 	TInt balance[KAccountIDs];
       
   373 	test(iAccs.CountL()==KAccountIDs);
       
   374 	for (iAccs.BeginningL();iAccs.NextL();)
       
   375 		{
       
   376 		iAccs.GetL();
       
   377 		TInt id=iAccs.ColInt(1);
       
   378 		balance[id]=iAccs.ColInt(3);
       
   379 		}
       
   380 	TInt transact=0;
       
   381 	for (iTrans.BeginningL();iTrans.NextL();)
       
   382 		{
       
   383 		++transact;
       
   384 		iTrans.GetL();
       
   385 		TInt from=iTrans.ColInt(2);
       
   386 		TInt to=iTrans.ColInt(3);
       
   387 		TInt amount=iTrans.ColInt(4);
       
   388 		balance[from]-=amount;
       
   389 		balance[to]+=amount;
       
   390 		}
       
   391 	test(transact==iTrans.CountL());
       
   392 	for (iAccs.BeginningL();iAccs.NextL();)
       
   393 		{
       
   394 		iAccs.GetL();
       
   395 		TInt id=iAccs.ColInt(1);
       
   396 		if (balance[id]!=iAccs.ColInt(2))
       
   397 			User::Panic(_L("Oh-oh"),4321);
       
   398 		}
       
   399 	}