searcher/tsrc/cpixsearchertest/src/multithreadtester.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 #include "multithreadtester.h"
       
    18 #include "RSearchServerSession.h"
       
    19 #include "CCPixIndexer.h"
       
    20 #include "CCPixSearcher.h"
       
    21 #include "CSearchDocument.h"
       
    22 #include <e32math.h>
       
    23 
       
    24 #define KIndexingWorkerCount 4
       
    25 #define KSearchingWorkerCount 16
       
    26 #define KTermDeviation 10 // The bigger this word, the more different term 
       
    27 #define KTermCountDeviation 10 // The bigger this word, the more terms per document
       
    28 _LIT( KContentsField, "Contents " ); 
       
    29 
       
    30 class CWorker : public CBase 
       
    31     {
       
    32 public: 
       
    33     CWorker() 
       
    34     : iWorkerId( iNextFreeWorkerId++ ), 
       
    35       iActive( EFalse ), 
       
    36       iThread(), 
       
    37       iSemaphore()
       
    38         {
       
    39         }
       
    40 
       
    41     void ConstructL() 
       
    42         {
       
    43         User::LeaveIfError( iSemaphore.CreateLocal( 0 ) ); 
       
    44         }
       
    45     
       
    46     ~CWorker() 
       
    47         {
       
    48         if ( iActive ) 
       
    49             {
       
    50             Finish(); 
       
    51             }
       
    52         iSemaphore.Close(); 
       
    53         }
       
    54     
       
    55     TInt WorkerId() 
       
    56         {
       
    57         return iWorkerId; 
       
    58         }
       
    59 
       
    60     TInt Error() 
       
    61         {
       
    62         return iError; 
       
    63         }
       
    64 
       
    65     virtual const TDesC& Name() = 0;
       
    66     
       
    67     void StartL() 
       
    68         {
       
    69         TThreadFunction function = CWorker::ThreadFunction; 
       
    70         
       
    71         User::LeaveIfError( iThread.Create( Name(), function, 2048, 0, this ) ); 
       
    72          
       
    73         iActive = ETrue;
       
    74         iThread.Resume(); 
       
    75         // Go thread go
       
    76     }
       
    77     
       
    78     void Finish() 
       
    79         {
       
    80         iActive = EFalse;
       
    81         DoCancel(); 
       
    82         iSemaphore.Wait(); 
       
    83         iThread.Close(); 
       
    84         }
       
    85     
       
    86 protected: 
       
    87 
       
    88     /**
       
    89      * For doing any required preparations in the original thread. 
       
    90      */
       
    91     virtual void DoPrepareL() = 0;
       
    92     virtual void DoCancel() = 0;
       
    93     virtual void DoRunL() = 0;
       
    94 
       
    95     void RunL() 
       
    96         {
       
    97         CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();
       
    98         CleanupStack::PushL(scheduler);
       
    99         CActiveScheduler::Install(scheduler);
       
   100 
       
   101         TRAP(iError, DoRunL());
       
   102         iSemaphore.Signal(); 
       
   103         
       
   104         CleanupStack::PopAndDestroy(scheduler);
       
   105         }
       
   106     
       
   107 public: 
       
   108     
       
   109     static TInt ThreadFunction(void *aThis) 
       
   110         {
       
   111         CTrapCleanup* cleanup = CTrapCleanup::New();
       
   112     
       
   113         TRAP_IGNORE
       
   114             ( 
       
   115             (reinterpret_cast<CWorker*>(aThis))->RunL();
       
   116             ); 
       
   117 
       
   118         delete cleanup;
       
   119         return KErrNone;
       
   120         }
       
   121     
       
   122 private: 
       
   123     
       
   124     TInt iWorkerId;     
       
   125     TInt iError; 
       
   126     static TInt iNextFreeWorkerId;  
       
   127     TBool iActive; 
       
   128     RThread iThread; 
       
   129     RSemaphore iSemaphore; 
       
   130     };
       
   131 
       
   132 
       
   133 TInt CWorker::iNextFreeWorkerId = 0;  
       
   134 
       
   135 /**
       
   136  * Returns random numbers so, that small numbers
       
   137  * are most common. Used to approximate the distribution
       
   138  * of real world words. In the distribution the probability that n is 
       
   139  * one of the numbers following i is 9 times as probable as that n is i. 
       
   140  * 
       
   141  * NOTE: Doesn't really follow the real distribution of words, because
       
   142  *       the word distribution follows Zipf's law and is not logarithmic.
       
   143  *       These things won't probably matter too much in any case. 
       
   144  */
       
   145 TInt LogRand( TInt aDeviation ) 
       
   146     {
       
   147     TInt rv = 0; 
       
   148     while ( Math::Random() % aDeviation ) rv++;
       
   149     return rv; 
       
   150     }
       
   151 
       
   152 /**
       
   153  * Worker, which continuously adds items to the index. Operates on its own
       
   154  * thread. 
       
   155  */
       
   156 class CIndexingWorker : public CWorker
       
   157     {
       
   158 public:
       
   159     CIndexingWorker() 
       
   160     :   iStop( EFalse ),
       
   161         iNextFreeUid( 0 ),
       
   162         iQualAppClass( 0 ),
       
   163         iAppClass( 0 ) 
       
   164         {
       
   165         }
       
   166     
       
   167     static CIndexingWorker* NewL( const TDesC& aAppClass ) 
       
   168         {
       
   169         CIndexingWorker* self = new ( ELeave ) CIndexingWorker(); 
       
   170         CleanupStack::PushL( self ); 
       
   171         self->ConstructL( aAppClass ); 
       
   172         CleanupStack::Pop( self ); 
       
   173         return self; 
       
   174         }
       
   175      
       
   176     void ConstructL( const TDesC& aQualAppClass ) 
       
   177         {
       
   178         CWorker::ConstructL(); 
       
   179         iQualAppClass = aQualAppClass.AllocL();
       
   180         iAppClass = aQualAppClass.Right( aQualAppClass.Length() - aQualAppClass.Find( _L( ":" ) ) - 1 ).AllocL();
       
   181         
       
   182         iName = HBufC::NewL( 512 );
       
   183         iName->Des().Append( _L( "indexer") ); 
       
   184         iName->Des().AppendNum( WorkerId() ); 
       
   185         iName->Des().Append( _L( "_") ); 
       
   186         iName->Des().Append( *iAppClass ); 
       
   187         }
       
   188 
       
   189     ~CIndexingWorker() 
       
   190         {
       
   191         delete iName; 
       
   192         delete iAppClass;
       
   193         delete iQualAppClass; 
       
   194         }
       
   195     
       
   196 public: // From Cworker
       
   197 
       
   198     virtual void DoPrepareL() {
       
   199         iStop = EFalse; 
       
   200     }
       
   201 
       
   202     virtual void DoCancel() {
       
   203         iStop = ETrue; 
       
   204     }
       
   205     
       
   206     virtual void DoRunL() 
       
   207         {
       
   208         RSearchServerSession session;
       
   209         User::LeaveIfError( session.Connect() );
       
   210         CleanupClosePushL( session ); 
       
   211         CCPixIndexer* indexer = CCPixIndexer::NewLC( session );
       
   212         indexer->OpenDatabaseL( *iQualAppClass );
       
   213         
       
   214         HBufC* buf = HBufC::NewLC( 1024*8 ); 
       
   215         
       
   216         while ( !iStop ) 
       
   217             {
       
   218             TBuf<64> docuid; 
       
   219             docuid.Append( _L("iw") ); 
       
   220             docuid.AppendNum( WorkerId() ); 
       
   221             docuid.Append( _L("_d") );  
       
   222             docuid.AppendNum( iNextFreeUid++ ); 
       
   223 
       
   224             CSearchDocument* doc = CSearchDocument::NewLC( docuid,
       
   225                                                            *iAppClass );
       
   226             
       
   227             buf->Des().Zero(); 
       
   228             TInt n = LogRand( KTermCountDeviation ) + 1; 
       
   229             for ( TInt i = 0; i < n; i++ ) 
       
   230                 {
       
   231                 buf->Des().AppendNum( LogRand( KTermDeviation ) ); 
       
   232                 if ( i + 1 < n ) 
       
   233                     {
       
   234                     buf->Des().Append( _L( " " ) );
       
   235                     }
       
   236                 }
       
   237                 
       
   238             doc->AddFieldL( KContentsField, *buf, CDocumentField::EStoreYes | 
       
   239                                                   CDocumentField::EIndexTokenized | 
       
   240                                                   CDocumentField::EAggregateNo ); 
       
   241             doc->AddExcerptL( *buf ); 
       
   242             
       
   243             indexer->AddL( *doc ); 
       
   244             
       
   245             CleanupStack::PopAndDestroy( doc ); 
       
   246             }
       
   247         CleanupStack::PopAndDestroy( buf ); 
       
   248         CleanupStack::PopAndDestroy( indexer ); 
       
   249         CleanupStack::PopAndDestroy(); // session 
       
   250         }
       
   251 
       
   252     virtual const TDesC& Name() {
       
   253         return *iName; 
       
   254     }
       
   255     
       
   256 private: 
       
   257     
       
   258     TBool iStop; 
       
   259     
       
   260     TInt iNextFreeUid; 
       
   261 
       
   262     HBufC* iQualAppClass;
       
   263 
       
   264     HBufC* iAppClass;
       
   265 
       
   266     HBufC* iName;
       
   267 
       
   268     };
       
   269 
       
   270 
       
   271 /**
       
   272  * A worker that commits normal searches to the given  search domain. 
       
   273  * Worker operates within its own thread.  
       
   274  */
       
   275 class CSearchingWorker : public CWorker
       
   276     {
       
   277 public: 
       
   278     CSearchingWorker() 
       
   279     :   iStop( EFalse ),
       
   280         iAppClass( 0 ), 
       
   281         iName( 0 )
       
   282         {
       
   283         }
       
   284     
       
   285     static CSearchingWorker* NewL( const TDesC& aAppClass ) 
       
   286         {
       
   287         CSearchingWorker* self = new ( ELeave ) CSearchingWorker(); 
       
   288         CleanupStack::PushL( self ); 
       
   289         self->ConstructL( aAppClass ); 
       
   290         CleanupStack::Pop( self ); 
       
   291         return self; 
       
   292         }
       
   293 
       
   294     
       
   295     void ConstructL( const TDesC& aAppClass ) 
       
   296         {   
       
   297         CWorker::ConstructL(); 
       
   298         
       
   299         iAppClass = aAppClass.AllocL(); 
       
   300 
       
   301         iName = HBufC::NewL( 512 );
       
   302         iName->Des().Append( _L( "searcher") ); 
       
   303         iName->Des().AppendNum( WorkerId() ); 
       
   304 /*      iName->Des().Append( _L( "_") ); 
       
   305         iName->Des().Append( aAppClass ); */
       
   306         }
       
   307     
       
   308     ~CSearchingWorker() 
       
   309         {
       
   310         delete iName;
       
   311         delete iAppClass; 
       
   312         }
       
   313 
       
   314 public: // From Cworker
       
   315 
       
   316     virtual void DoPrepareL() 
       
   317         {
       
   318         iStop = EFalse; 
       
   319         }
       
   320 
       
   321     virtual void DoCancel() 
       
   322         {
       
   323         iStop = ETrue; 
       
   324         }
       
   325     
       
   326     virtual void DoRunL() 
       
   327         {
       
   328         RSearchServerSession session;
       
   329         User::LeaveIfError( session.Connect() );
       
   330         CleanupClosePushL( session ); 
       
   331         CCPixSearcher* searcher = CCPixSearcher::NewLC( session, KContentsField );
       
   332         
       
   333         searcher->OpenDatabaseL( *iAppClass );
       
   334         
       
   335         while ( !iStop ) 
       
   336             {
       
   337             TBuf<64> num; 
       
   338             num.AppendNum( LogRand( KTermDeviation ) );  
       
   339             TInt n = searcher->SearchL( num ); 
       
   340             for ( TInt i = 0; i < n; i++ ) 
       
   341                 {
       
   342                 TRAP_IGNORE( delete searcher->GetDocumentL( i++ ); ); 
       
   343                 }
       
   344             }
       
   345         CleanupStack::PopAndDestroy( searcher ); // session
       
   346         CleanupStack::PopAndDestroy(); // session
       
   347         }
       
   348         
       
   349     virtual const TDesC& Name() 
       
   350         {
       
   351         return *iName; 
       
   352         }
       
   353     
       
   354 private:
       
   355     
       
   356     TBool iStop; 
       
   357     HBufC* iAppClass; 
       
   358     HBufC* iName; 
       
   359     };
       
   360 
       
   361 
       
   362 void CTestMultiThreading::setUp() 
       
   363     {
       
   364     }
       
   365 
       
   366 void CTestMultiThreading::tearDown() 
       
   367     {
       
   368     }
       
   369 
       
   370 void CTestMultiThreading::PrepareL() 
       
   371     {
       
   372     RSearchServerSession session;
       
   373     User::LeaveIfError( session.Connect() ); 
       
   374     CleanupClosePushL( session ); 
       
   375     
       
   376     // First database has one reader and one or two searchers, what 
       
   377     // is something that can be expected in the actual device
       
   378     User::LeaveIfError
       
   379         (
       
   380         session.DefineVolume( _L( "@df:root test expected" ), 
       
   381                               _L( "c:\\data\\indexing\\indexdb\\root\\test\\expected" ) )
       
   382         ); 
       
   383     
       
   384     // Second database has one reader and one or two searchers, what 
       
   385     // is quite uncommon example and mainly used to stress the search server
       
   386     User::LeaveIfError
       
   387         (
       
   388         session.DefineVolume( _L( "@df:root test busy" ),
       
   389                               _L( "c:\\data\\indexing\\indexdb\\root\\test\\busy" ) )
       
   390         );
       
   391         
       
   392     CCPixIndexer* indexer = CCPixIndexer::NewLC( session );
       
   393     indexer->OpenDatabaseL( _L( "@df:root test expected" ) );
       
   394     indexer->ResetL(); 
       
   395     indexer->OpenDatabaseL( _L( "@df:root test busy" ) );
       
   396     indexer->ResetL(); 
       
   397     CleanupStack::PopAndDestroy( indexer); 
       
   398     CleanupStack::PopAndDestroy(); // session  
       
   399 
       
   400     // 
       
   401     // Indexers
       
   402     // 
       
   403     
       
   404     // Indexer with one's own index
       
   405     iWorkers->Append( CIndexingWorker::NewL( _L( "@df:root test expected" ) ) );
       
   406     
       
   407     // 3 indexers in the same index
       
   408     iWorkers->Append( CIndexingWorker::NewL( _L( "@df:root test busy" ) ) );
       
   409     iWorkers->Append( CIndexingWorker::NewL( _L( "@df:root test busy" ) ) );
       
   410     iWorkers->Append( CIndexingWorker::NewL( _L( "@df:root test busy" ) ) );
       
   411     
       
   412     // = 4 indexers in total 
       
   413     
       
   414     // 
       
   415     // Searchers
       
   416     // 
       
   417     
       
   418     // Multisearcher
       
   419     iWorkers->Append( CSearchingWorker::NewL( _L( "root test" ) ) );
       
   420 
       
   421     // Search qualified index
       
   422     iWorkers->Append( CSearchingWorker::NewL( _L( "@df:root test expected") ) );
       
   423 
       
   424     // Search big the busy index
       
   425     iWorkers->Append( CSearchingWorker::NewL( _L( "@df:root test busy" ) ) );
       
   426     iWorkers->Append( CSearchingWorker::NewL( _L( "@df:root test busy" ) ) );
       
   427     iWorkers->Append( CSearchingWorker::NewL( _L( "root test busy" ) ) );
       
   428     
       
   429     // = 5 searchers in total
       
   430     }
       
   431 
       
   432 void CTestMultiThreading::Wait(TInt aSeconds) 
       
   433     {
       
   434     RTimer timer; 
       
   435     TRequestStatus timerStatus; 
       
   436     timer.CreateLocal();        
       
   437     CleanupClosePushL( timer ); 
       
   438     
       
   439     timer.After( timerStatus, aSeconds * 1000 * 1000 ); 
       
   440     User::WaitForRequest(timerStatus); 
       
   441     
       
   442     CleanupStack::PopAndDestroy(); // timer 
       
   443     }
       
   444 
       
   445 void CTestMultiThreading::RunL() 
       
   446     {
       
   447     for ( TInt i = 0; i < iWorkers->Count(); i++ ) 
       
   448         {
       
   449         (*iWorkers)[i]->StartL(); 
       
   450         }
       
   451     
       
   452     Wait( 5 ); // Wait for 5 seconds
       
   453     
       
   454     for ( TInt i = 0; i < iWorkers->Count(); i++ ) 
       
   455         {
       
   456         (*iWorkers)[i]->Finish(); 
       
   457         if ( (*iWorkers)[i]->Error() != KErrNone ) 
       
   458             {
       
   459             TBuf8<512> msg; 
       
   460             const TDesC& name = (*iWorkers)[i]->Name();
       
   461             for ( TInt c = 0; c < name.Length(); c++ ) {
       
   462                 msg.Append( name[c] ); 
       
   463             }
       
   464             msg.Append( _L8( " failed with" ) );
       
   465             msg.AppendNum( (*iWorkers)[i]->Error() );
       
   466             //TS_FAIL( reinterpret_cast<const char*>( msg.PtrZ() ) ); 
       
   467             }
       
   468         }
       
   469     }
       
   470 
       
   471 void CTestMultiThreading::Finish() 
       
   472     {
       
   473     iWorkers->ResetAndDestroy();
       
   474     }
       
   475 
       
   476 void CTestMultiThreading::DoTestMultiThreadingL() 
       
   477     {
       
   478     iWorkers = new ( ELeave ) RPointerArray<CWorker>(); 
       
   479     CleanupStack::PushL( iWorkers ); 
       
   480     CleanupClosePushL( *iWorkers ); 
       
   481     PrepareL(); 
       
   482     TRAPD( err, RunL() ); 
       
   483     Finish(); 
       
   484     User::LeaveIfError( err ); 
       
   485     CleanupStack::PopAndDestroy( iWorkers ); 
       
   486     CleanupStack::PopAndDestroy(); // iWorkers  
       
   487     }