searcher/tsrc/robustnesstest/src/cstressworker.cpp
changeset 0 671dee74050a
equal deleted inserted replaced
-1:000000000000 0:671dee74050a
       
     1 /*
       
     2 * Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 #include "CStressWorker.h"
       
    19 #include "RSearchServerSession.h"
       
    20 #include "CCPixIndexer.h"
       
    21 #include "CCPixSearcher.h"
       
    22 #include "CSearchDocument.h"
       
    23 #include <e32math.h>
       
    24 #include "CLog.h"
       
    25 #include "MCPixSearcherObserver.h"
       
    26 #include "robustnesstest.pan"
       
    27 
       
    28 #include "CWorker.h"
       
    29 #include "CIndexingWorker.h"
       
    30 #include "CSearchingWorker.h"
       
    31 
       
    32 #define KLockWaitSeconds 5 // wait for some good time 
       
    33 
       
    34 #define KLockWaitMicroSeconds KLockWaitSeconds * 1000 * 1000 // wait for some good time 
       
    35 
       
    36 #define KWaitAfterCancellingSeconds 10 // wait for some good time 
       
    37 
       
    38 #define KWaitFinishSeconds 10 // wait for some good time 
       
    39 
       
    40 #define KWaitFinishMicroSeconds KWaitFinishSeconds * 1000 * 1000 // wait for some good time 
       
    41 
       
    42 
       
    43 CStressWorker::CStressWorker( MLog& aLog,
       
    44 							  TInt aPreIndex, 
       
    45 							  TInt aIndexAverageItems,
       
    46 							  TBool aIndexingEnabled,
       
    47 							  TBool aDeletesEnabled,
       
    48 						      TBool aSearchersEnabled, 
       
    49 						      TBool aCancellingEnabled,
       
    50 						      TInt aIndexerSleep, 
       
    51 						      TInt aSearcherSleep )
       
    52 :   iLog( aLog ),
       
    53     iWorkers(),
       
    54     iIsActive( EFalse ),
       
    55 	iPreIndex         ( aPreIndex ),		
       
    56 	iIndexAverageItems( aIndexAverageItems ), 
       
    57 	iIndexingEnabled  ( aIndexingEnabled ),
       
    58 	iDeletesEnabled	  ( aDeletesEnabled ),
       
    59 	iSearchersEnabled ( aSearchersEnabled ),
       
    60 	iCancellingEnabled( aCancellingEnabled ),
       
    61 	iIndexerSleep	  ( aIndexerSleep), 
       
    62 	iSearcherSleep    (	aSearcherSleep )
       
    63 	{
       
    64 	}
       
    65 
       
    66 CStressWorker::~CStressWorker()
       
    67 	{
       
    68 	iWorkers.ResetAndDestroy();
       
    69 	iWorkers.Close(); 
       
    70 	}
       
    71 
       
    72 void CStressWorker::ConstructL()
       
    73 	{
       
    74 	}
       
    75 
       
    76 void CStressWorker::StartWorkersL() 
       
    77 	{
       
    78 
       
    79 	// 
       
    80 	// Indexers
       
    81 	// 
       
    82 	
       
    83 	
       
    84 	if ( iIndexingEnabled ) 
       
    85 		{
       
    86 		// Indexer working with normal index
       
    87 		iWorkers.Append( CIndexingWorker::NewL( KNormalVolume, iDeletesEnabled, iIndexAverageItems, iIndexerSleep ) );
       
    88 			
       
    89 		// 3 indexers working with busy index
       
    90 		iWorkers.Append( CIndexingWorker::NewL( KBusyVolume, iDeletesEnabled, iIndexAverageItems, iIndexerSleep ) );
       
    91 		iWorkers.Append( CIndexingWorker::NewL( KBusyVolume, iDeletesEnabled, iIndexAverageItems, iIndexerSleep ) );
       
    92 		iWorkers.Append( CIndexingWorker::NewL( KBusyVolume, iDeletesEnabled, iIndexAverageItems, iIndexerSleep ) );
       
    93 		
       
    94 		// = 4 indexers in total 
       
    95 		}
       
    96 	
       
    97 	if ( iSearchersEnabled ) 
       
    98 		{
       
    99 		// 
       
   100 		// Searchers
       
   101 		// 
       
   102 		
       
   103 		// Multisearcher
       
   104 		iWorkers.Append( CSearchingWorker::NewL( KTestBaseAppClass, iSearcherSleep ) );
       
   105 
       
   106 		// Search normal index 
       
   107 		iWorkers.Append( CSearchingWorker::NewL( KNormalVolume, iSearcherSleep, iCancellingEnabled ) );
       
   108 
       
   109 		// Search big the busy index
       
   110 		iWorkers.Append( CSearchingWorker::NewL( KBusyVolume, iSearcherSleep ) );
       
   111 		iWorkers.Append( CSearchingWorker::NewL( KBusyVolume, iSearcherSleep, EFalse, iCancellingEnabled ) );
       
   112 		iWorkers.Append( CSearchingWorker::NewL( KBusyBaseAppClass, iSearcherSleep  ) );
       
   113 
       
   114 		// = 5 searchers in total
       
   115 		}
       
   116 	
       
   117 	for ( TInt i = 0; i < iWorkers.Count(); i++ ) 
       
   118 		{
       
   119 		iWorkers[i]->StartL();
       
   120 		}
       
   121 	}
       
   122 
       
   123 void CStressWorker::PrepareIndexL()
       
   124 	{
       
   125 	RSearchServerSession session;
       
   126 	User::LeaveIfError( session.Connect() ); 
       
   127 	CleanupClosePushL( session ); 
       
   128 	
       
   129 	// First database has one reader and one or two searchers, what 
       
   130 	// is something that can be expected in the actual device
       
   131 	User::LeaveIfError
       
   132 		(
       
   133 		session.DefineVolume( KNormalVolume, 
       
   134 							  KNormalIndexDirectory )
       
   135 		); 
       
   136 	
       
   137 	// Second database has a number of searchers and indexers. 
       
   138 	User::LeaveIfError
       
   139 		(
       
   140 		session.DefineVolume( KBusyVolume,
       
   141 							  KBusyIndexDirectory )
       
   142 		);
       
   143 	
       
   144 	if ( iPreIndex ) iLog.LogL( _L( "preparing index") ); 
       
   145 
       
   146 	CCPixIndexer* indexer = CCPixIndexer::NewLC( session );
       
   147 	indexer->OpenDatabaseL( KNormalVolume );
       
   148 	indexer->ResetL();
       
   149 	
       
   150 	HBufC* buf = HBufC::NewLC( 4 * 1024 ); 
       
   151 	TPtr pbuf( buf->Des() ); 
       
   152 	
       
   153 	for ( TInt i = 0; i < iPreIndex; i++ ) 
       
   154 		{
       
   155 		indexer->AddL( *GenerateDocumentLC( iIndexAverageItems, 
       
   156 										    KNormalBaseAppClass, 
       
   157 										    pbuf ) );
       
   158 		CleanupStack::PopAndDestroy(); 
       
   159 		}
       
   160 	
       
   161 	indexer->FlushL();
       
   162 	
       
   163 	indexer->OpenDatabaseL( KBusyVolume );
       
   164 	indexer->ResetL(); 
       
   165 	
       
   166 	for ( TInt i = 0; i < iPreIndex; i++ ) 
       
   167 		{
       
   168 		indexer->AddL( *GenerateDocumentLC( iIndexAverageItems, 
       
   169 										    KBusyBaseAppClass, 
       
   170 										    pbuf ) );
       
   171 		CleanupStack::PopAndDestroy(); 
       
   172 		}
       
   173 	
       
   174 	CleanupStack::PopAndDestroy( buf );
       
   175 	
       
   176 	indexer->FlushL();
       
   177 	CleanupStack::PopAndDestroy( indexer ); 
       
   178 	CleanupStack::PopAndDestroy(); // session 
       
   179 	}
       
   180 
       
   181 void CStressWorker::StartL()
       
   182 	{
       
   183 	
       
   184 	PrepareIndexL(); 
       
   185 	
       
   186 	TRAPD( err, StartWorkersL() ); 
       
   187 	
       
   188 	if ( err != KErrNone )
       
   189 		{
       
   190 		iWorkers.ResetAndDestroy();
       
   191 		User::Leave( err ); 
       
   192 		}
       
   193 	else 
       
   194 		{
       
   195 		iIsActive = ETrue; 
       
   196 		}
       
   197 	}
       
   198 
       
   199 void CStressWorker::DoFinishL()
       
   200 	{
       
   201 	for ( TInt i = 0; i < iWorkers.Count(); i++ ) 
       
   202 		{
       
   203 		iWorkers[i]->Cancel();
       
   204 		}
       
   205 	
       
   206 	User::After( KWaitAfterCancellingSeconds * 1000 * 1000 );
       
   207 	
       
   208 	int running = iWorkers.Count();
       
   209 	TInt round = 0;
       
   210 	for (; round < 3 && running ; round++ ) 
       
   211 		{
       
   212 		switch (round) 
       
   213 			{
       
   214 			case 1: 
       
   215 			case 2: 
       
   216 				iLog.LogL( _L( "Retrying to stop workers." ) );
       
   217 				break;
       
   218 			}
       
   219 		for ( TInt i = 0; i < iWorkers.Count(); i++ ) 
       
   220 			{
       
   221 			if ( iWorkers[i]->IsActive() )
       
   222 				{
       
   223 				if ( iWorkers[i]->TryJoin( KWaitFinishMicroSeconds ) == KErrNone )
       
   224 					{
       
   225 					running--;
       
   226 					if ( round > 0 )
       
   227 						{
       
   228 						iLog.LogL( _L( "worker '%S' finished" ),
       
   229 								   &iWorkers[i]->Name() );
       
   230 						}
       
   231 					}
       
   232 				else 
       
   233 					{
       
   234 					iLog.LogL( _L( "worker '%S' failed to exit within %d s" ),
       
   235 							   &iWorkers[i]->Name(),
       
   236 							   KWaitFinishSeconds  );
       
   237 					}
       
   238 				}
       
   239 			}
       
   240 		}
       
   241 
       
   242 	if ( running ) 
       
   243 		{  
       
   244 		iLog.LogL( _L( "Deadlock? %d worker(s) failed to exit." ),
       
   245 				   running );
       
   246 		
       
   247 		iLog.LogL( _L( "Terminating workers forcefully (may cause leaks)" ) );
       
   248 		
       
   249 		for ( TInt i = 0; i < iWorkers.Count(); i++ ) 
       
   250 			{
       
   251 			if ( iWorkers[i]->IsActive() )
       
   252 				{
       
   253 				iWorkers[i]->Terminate();
       
   254 				iWorkers[i]->Unlock(); // So that we can check the records. 
       
   255 				iLog.LogL( _L( "terminated worker '%S'." ),
       
   256 						   &iWorkers[i]->Name() ); 
       
   257 				}
       
   258 			}
       
   259 
       
   260 		}
       
   261 	else if (round > 1) 
       
   262 		{
       
   263 		iLog.LogL( _L( "All workers finished successfully." ) ); 
       
   264 		}
       
   265 
       
   266 	ReportL();
       
   267 	
       
   268 	}
       
   269 
       
   270 TBool CStressWorker::ReportL()
       
   271 	{
       
   272 	TBool error = EFalse; 
       
   273 	for ( TInt i = 0; i < iWorkers.Count(); i++ ) 
       
   274 		{
       
   275 		if ( iWorkers[i]->Error() != KErrNone && 
       
   276 			 iWorkers[i]->IsReported() == EFalse )
       
   277 			{
       
   278 			TDateTime time = iWorkers[i]->ExitTime().DateTime();
       
   279 			
       
   280 			TBuf<64> buf; 
       
   281 			buf.AppendNumFixedWidth( (TUint)time.Hour(), EDecimal, 2 );
       
   282 			buf.Append(_L(":"));
       
   283 			buf.AppendNumFixedWidth( (TUint)time.Minute(), EDecimal, 2 );
       
   284 			buf.Append(_L(":"));
       
   285 			buf.AppendNumFixedWidth( (TUint)time.Second(), EDecimal, 2 );
       
   286 			buf.Append(_L("."));
       
   287 			buf.AppendNumFixedWidth( (TUint)time.MicroSecond(), EDecimal, 3 );
       
   288 			
       
   289 			iLog.LogL( _L( "worker '%S' failed with %d at %S" ),
       
   290 					   &iWorkers[i]->Name(),
       
   291 					   iWorkers[i]->Error(),
       
   292 					   &buf  );
       
   293 			iWorkers[i]->SetReported();
       
   294 			error = ETrue; 
       
   295 			}
       
   296 		}
       
   297 	return error;
       
   298 	}
       
   299 
       
   300 
       
   301 void CStressWorker::AppendOpStatsL( RPointerArray<HBufC8>& aStats, TInt aOperations, TInt64 aOperationsMicroSeconds ) 
       
   302 	{
       
   303 	HBufC8* buf = HBufC8::NewL( 64 ); 
       
   304 	buf->Des().AppendNum( aOperations ); 
       
   305 	aStats.Append( buf );
       
   306 	buf = HBufC8::NewL( 64 ); 
       
   307 	if ( aOperations > 0 ) 
       
   308 		{
       
   309 		buf->Des().AppendNum( (aOperationsMicroSeconds / 1000) / aOperations ); 
       
   310 		}
       
   311 	else 
       
   312 		{
       
   313 		buf->Des().Append( _L8( "NaN") ); 
       
   314 		}
       
   315 	aStats.Append( buf );
       
   316 	}
       
   317 
       
   318 void CStressWorker::AppendOpStatsL( RPointerArray<HBufC8>& aStats, TInt aOperations, TInt64 aOperationsMicroSeconds, TInt64 aOperationsPeakMicroSeconds ) 
       
   319 	{
       
   320 	HBufC8* buf = HBufC8::NewL( 64 ); 
       
   321 	AppendOpStatsL( aStats, aOperations, aOperationsMicroSeconds );
       
   322 	
       
   323 	if ( aOperations > 0 )
       
   324 		{
       
   325 		buf->Des().AppendNum( aOperationsPeakMicroSeconds / 1000 ); 
       
   326 		}
       
   327 	else 
       
   328 		{
       
   329 		buf->Des().Append( _L8( "NaN") ); 
       
   330 		}
       
   331 	aStats.Append( buf );
       
   332 	}
       
   333 
       
   334 TInt CStressWorker::DirectorySizeL( const TDesC& aDirectory )
       
   335 	{
       
   336 
       
   337 	RFs fs; 
       
   338 	User::LeaveIfError( fs.Connect() ); 
       
   339 	CleanupClosePushL( fs ); 
       
   340 	
       
   341 	TBuf<256> buf; 
       
   342 	buf.Append( aDirectory ); 
       
   343 	buf.Append( _L( "\\*" ) );  
       
   344 	
       
   345 	// Make sure, that the index is not under merging or optimization operations
       
   346 	
       
   347 	CDir* dir; 
       
   348 	TInt err = fs.GetDir( buf,        
       
   349 				          KEntryAttMaskSupported,
       
   350 						  ESortByName,
       
   351 						  dir );
       
   352 	TInt size = 0; 
       
   353 	if ( err == KErrNone ) 
       
   354 		{
       
   355 		for (TInt i=0;i<dir->Count();i++)
       
   356 			{
       
   357 			size += (*dir)[i].iSize;
       
   358 			}
       
   359 		
       
   360 		delete dir;
       
   361 		}
       
   362 	else 
       
   363 		{
       
   364 		// It is ok, if directory was not found.
       
   365 		}
       
   366 	
       
   367 	CleanupStack::PopAndDestroy(); // fs
       
   368 	
       
   369 	return size;
       
   370 	}
       
   371 
       
   372 _LIT( KIndexZero, "\\_0" ); 
       
   373 _LIT( KIndexOne, "\\_1" ); 
       
   374 
       
   375 TInt CStressWorker::IndexSizeL( const TDesC& aDirectory )
       
   376 	{
       
   377 	TInt size = 0; 
       
   378 	TBuf<256> buf;
       
   379 	buf.Append( aDirectory ); 
       
   380 	buf.Append( KIndexZero ); 
       
   381 	size += DirectorySizeL( buf ); 
       
   382 	buf.Zero();
       
   383 	buf.Append( aDirectory ); 
       
   384 	buf.Append( KIndexOne ); 
       
   385 	size += DirectorySizeL( buf ); 
       
   386 	return size;
       
   387 	}
       
   388 
       
   389 void CStressWorker::AppendStatsLabelsL( RPointerArray<HBufC8>& aStats )
       
   390 	{
       
   391 	aStats.Append( _L8( "norm sz").AllocL() ); 
       
   392 	aStats.Append( _L8( "busy sz").AllocL() );
       
   393 	
       
   394 	if ( iIndexingEnabled )
       
   395 		{
       
   396 		aStats.Append( _L8( "adds").AllocL() ); 
       
   397 		aStats.Append( _L8( "ms/op").AllocL() ); 
       
   398 		aStats.Append( _L8( "deletes").AllocL() ); 
       
   399 		aStats.Append( _L8( "ms/op").AllocL() );
       
   400 		}
       
   401 	if ( iSearchersEnabled ) 
       
   402 		{
       
   403 		aStats.Append( _L8( "searches").AllocL() ); 
       
   404 		aStats.Append( _L8( "ms/op").AllocL() ); 
       
   405 		aStats.Append( _L8( "peak").AllocL() ); 
       
   406 
       
   407 		aStats.Append( _L8( "getdocs").AllocL() ); 
       
   408 		aStats.Append( _L8( "ms/op").AllocL() ); 
       
   409 		aStats.Append( _L8( "peak").AllocL() ); 
       
   410 
       
   411 		aStats.Append( _L8( "terms").AllocL() ); 
       
   412 		aStats.Append( _L8( "ms/op").AllocL() ); 
       
   413 		aStats.Append( _L8( "peak").AllocL() ); 
       
   414 
       
   415 		aStats.Append( _L8( "getterms").AllocL() ); 
       
   416 		aStats.Append( _L8( "ms/op").AllocL() ); 
       
   417 		aStats.Append( _L8( "peak").AllocL() ); 
       
   418 		}
       
   419 	}
       
   420 
       
   421 
       
   422 void CStressWorker::AppendStatsInsideLocksL( RPointerArray<HBufC8>& aStats, const RArray<TBool>& aLocked ) 
       
   423 	{
       
   424 	TInt additions = 0; 
       
   425 	TInt64 additionsMicroSeconds = 0;
       
   426 		
       
   427 	TInt deletes = 0; 
       
   428 	TInt64 deletesMicroSeconds = 0; 
       
   429 
       
   430 	TInt searches = 0; 
       
   431 	TInt64 searchesMicroSeconds = 0; 
       
   432 	TInt64 searchesPeakMicroSeconds = 0; 
       
   433 	
       
   434 	TInt termSearches = 0; 
       
   435 	TInt64 termSearchesMicroSeconds = 0; 
       
   436 	TInt64 termSearchesPeakMicroSeconds = 0; 
       
   437 
       
   438 	TInt docs = 0; 
       
   439 	TInt64 docsMicroSeconds = 0; 
       
   440 	TInt64 docsPeakMicroSeconds = 0; 
       
   441 
       
   442 	TInt terms = 0; 
       
   443 	TInt64 termsMicroSeconds = 0; 
       
   444 	TInt64 termsPeakMicroSeconds = 0; 
       
   445 
       
   446 	for ( TInt i = 0; i < iWorkers.Count(); i++ ) 
       
   447 		{
       
   448 		if ( aLocked[i] )
       
   449 			{
       
   450 			// Extract statistics only, if worker was successfully locked. 
       
   451 			if ( dynamic_cast<CIndexingWorker*>( iWorkers[i] ) ) 
       
   452 				{
       
   453 				CIndexingWorker* worker = dynamic_cast<CIndexingWorker*>( iWorkers[i] ); 
       
   454 				additions 				+= worker->ConsumeAdditions(); 
       
   455 				additionsMicroSeconds 	+= worker->ConsumeAdditionsMicroSeconds(); 
       
   456 				deletes					+= worker->ConsumeDeletes(); 
       
   457 				deletesMicroSeconds 	+= worker->ConsumeDeletesMicroSecond(); 
       
   458 				}
       
   459 			if ( dynamic_cast<CSearchingWorker*>( iWorkers[i] ) ) 
       
   460 				{
       
   461 				CSearchingWorker* worker = dynamic_cast<CSearchingWorker*>( iWorkers[i] );
       
   462 				searches 					+= worker->ConsumeSearches(); 
       
   463 				searchesMicroSeconds 		+= worker->ConsumeSearchesMicroSeconds(); 
       
   464 				searchesPeakMicroSeconds 	+= worker->ConsumeSearchesPeakMicroSeconds();
       
   465 				
       
   466 				termSearches 				+= worker->ConsumeTermSearches(); 
       
   467 				termSearchesMicroSeconds	+= worker->ConsumeTermSearchesMicroSeconds(); 
       
   468 				termSearchesPeakMicroSeconds+= worker->ConsumeTermSearchesPeakMicroSeconds(); 
       
   469 
       
   470 				docs 						+= worker->ConsumeDocs(); 
       
   471 				docsMicroSeconds			+= worker->ConsumeDocsMicroSeconds(); 
       
   472 				docsPeakMicroSeconds		+= worker->ConsumeDocsPeakMicroSeconds(); 
       
   473 
       
   474 				terms 						+= worker->ConsumeTerms(); 
       
   475 				termsMicroSeconds			+= worker->ConsumeTermsMicroSeconds(); 
       
   476 				termsPeakMicroSeconds		+= worker->ConsumeTermsPeakMicroSeconds(); 
       
   477 				}
       
   478 			}
       
   479 		}
       
   480 	HBufC8* buf = HBufC8::NewL( 64 ); 
       
   481 	buf->Des().AppendNum( IndexSizeL( KNormalIndexDirectory ) ); 
       
   482 	aStats.Append( buf );
       
   483 
       
   484 	buf = HBufC8::NewL( 64 ); 
       
   485 	buf->Des().AppendNum( IndexSizeL( KBusyIndexDirectory ) ); 
       
   486 	aStats.Append( buf );
       
   487 	
       
   488 	if ( iIndexingEnabled )
       
   489 		{
       
   490 		AppendOpStatsL( aStats, additions, additionsMicroSeconds ); 
       
   491 		AppendOpStatsL( aStats, deletes, deletesMicroSeconds );
       
   492 		}
       
   493 	
       
   494 	if ( iSearchersEnabled ) 
       
   495 		{
       
   496 		AppendOpStatsL( aStats, searches, searchesMicroSeconds, searchesPeakMicroSeconds ); 
       
   497 		AppendOpStatsL( aStats, docs, docsMicroSeconds, docsPeakMicroSeconds ); 
       
   498 		AppendOpStatsL( aStats, termSearches, termSearchesMicroSeconds, termSearchesPeakMicroSeconds );
       
   499 		AppendOpStatsL( aStats, terms, termsMicroSeconds, termsPeakMicroSeconds ); 
       
   500 		}
       
   501 	
       
   502 	}
       
   503 
       
   504 void CStressWorker::AppendStatsL( RPointerArray<HBufC8>& aStats )
       
   505 	{
       
   506 	RArray<TBool> locked;
       
   507 	CleanupClosePushL( locked ); 
       
   508 	
       
   509 	// First of first: lock all workers that can be locked and request
       
   510 	// their entries
       
   511 	
       
   512 	for ( TInt i = 0; i < iWorkers.Count(); i++ ) 
       
   513 		{
       
   514 		if ( iWorkers[i]->TryLock( KLockWaitMicroSeconds ) == KErrNone )
       
   515 			{
       
   516 			locked.Append( ETrue ); 
       
   517 			}
       
   518 		else 
       
   519 			{
       
   520 			TRAP_IGNORE
       
   521 				( 
       
   522 				iLog.LogL( _L( "worker '%S' failed to respond within %d s" ),
       
   523 						   &iWorkers[i]->Name(),
       
   524 						   KLockWaitSeconds );
       
   525 				)
       
   526 			locked.Append( EFalse ); 
       
   527 			}
       
   528 		}
       
   529 	
       
   530 	TRAPD( err, AppendStatsInsideLocksL( aStats, locked ) ); 
       
   531 	
       
   532 	for ( TInt i = 0; i < iWorkers.Count(); i++ ) 
       
   533 		{
       
   534 		if ( locked[i] ) 
       
   535 			{
       
   536 			iWorkers[i]->Unlock();
       
   537 			}
       
   538 		}
       
   539 	
       
   540 	CleanupStack::PopAndDestroy(); // locked
       
   541 	
       
   542 	User::LeaveIfError( err ); 
       
   543 }
       
   544 
       
   545 TInt CStressWorker::Finish()
       
   546 	{
       
   547 	if ( iIsActive ) 
       
   548 		{
       
   549 		TRAPD( err, DoFinishL() ); 
       
   550 		if ( err != KErrNone ) 
       
   551 			{
       
   552 			iWorkers.ResetAndDestroy();
       
   553 			}
       
   554 		iIsActive = EFalse; 
       
   555 		return err; 
       
   556 		}
       
   557 	return KErrNone; 
       
   558 	}
       
   559 
       
   560 TBool CStressWorker::IsActive() 
       
   561 	{
       
   562 	return iIsActive; 
       
   563 	}