View Javadoc
1   package org.apache.maven.index;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0    
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.util.concurrent.atomic.AtomicInteger;
25  
26  import junit.framework.Assert;
27  
28  import org.apache.lucene.search.Query;
29  import org.apache.maven.index.context.IndexingContext;
30  import org.apache.maven.index.expr.UserInputSearchExpression;
31  
32  public class ConcurrentUseTest
33      extends AbstractNexusIndexerTest
34  {
35      public static final int THREAD_COUNT = 10;
36  
37      protected File repo = new File( getBasedir(), "src/test/repo" );
38  
39      @Override
40      protected void prepareNexusIndexer( NexusIndexer nexusIndexer )
41          throws Exception
42      {
43          context =
44              nexusIndexer.addIndexingContext( "test-default", "test", repo, indexDir, null, null, DEFAULT_CREATORS );
45  
46          assertNull( context.getTimestamp() ); // unknown upon creation
47  
48          nexusIndexer.scan( context );
49  
50          assertNotNull( context.getTimestamp() );
51      }
52  
53      protected IndexUserThread createThread( final ArtifactInfo ai )
54      {
55          // we search and modify same context concurrently
56          return new IndexUserThread( this, nexusIndexer, context, context, ai );
57      }
58  
59      public void testConcurrency()
60          throws Exception
61      {
62          IndexUserThread[] threads = new IndexUserThread[THREAD_COUNT];
63  
64          ArtifactInfo ai =
65              new ArtifactInfo( "test-default", "org.apache.maven.indexer", "index-concurrent-artifact", "", null, "jar" );
66  
67          for ( int i = 0; i < THREAD_COUNT; i++ )
68          {
69              threads[i] = createThread( ai );
70  
71              threads[i].start();
72          }
73  
74          Thread.sleep( 5000 );
75  
76          boolean thereWereProblems = false;
77  
78          int totalAdded = 0;
79  
80          for ( int i = 0; i < THREAD_COUNT; i++ )
81          {
82              threads[i].stopThread();
83  
84              threads[i].join();
85  
86              thereWereProblems = thereWereProblems || threads[i].hadProblem();
87  
88              totalAdded += threads[i].getAdded();
89          }
90  
91          Assert.assertFalse( "Not all thread did clean job!", thereWereProblems );
92  
93          context.commit();
94  
95          // sleep more than bottleWarmer does, to be sure commit and reopen happened
96          // BottleWarmer sleeps 1000 millis
97          Thread.sleep( 2000 );
98  
99          //
100 
101         Query q = nexusIndexer.constructQuery( MAVEN.GROUP_ID, new UserInputSearchExpression( ai.getGroupId() ) );
102 
103         FlatSearchResponse result = nexusIndexer.searchFlat( new FlatSearchRequest( q, context ) );
104 
105         Assert.assertEquals( "All added should be found after final commit!", totalAdded, result.getTotalHitsCount() );
106     }
107 
108     // ==
109 
110     private static final AtomicInteger versionSource = new AtomicInteger( 1 );
111 
112     protected void addToIndex( final NexusIndexer nexusIndexer, final IndexingContext indexingContext )
113         throws IOException
114     {
115         final ArtifactInfo artifactInfo =
116             new ArtifactInfo( "test-default", "org.apache.maven.indexer", "index-concurrent-artifact", "1."
117                 + versionSource.getAndIncrement(), null , "jar");
118 
119         final ArtifactContext ac = new ArtifactContext( null, null, null, artifactInfo, artifactInfo.calculateGav() );
120 
121         nexusIndexer.addArtifactToIndex( ac, indexingContext );
122     }
123 
124     protected void deleteFromIndex( final NexusIndexer nexusIndexer, final IndexingContext indexingContext )
125         throws IOException
126     {
127         // TODO: delete some of those already added
128         // artifactInfo.version = "1." + String.valueOf( versionSource.getAndIncrement() );
129         //
130         // ac = new ArtifactContext( null, null, null, artifactInfo, artifactInfo.calculateGav() );
131         //
132         // nexusIndexer.deleteArtifactFromIndex( ac, indexingContext );
133         //
134         // deleted++;
135     }
136 
137     protected int readIndex( final NexusIndexer nexusIndexer, final IndexingContext indexingContext )
138         throws IOException
139     {
140         final Query q =
141             nexusIndexer.constructQuery( MAVEN.GROUP_ID, new UserInputSearchExpression( "org.apache.maven.indexer" ) );
142 
143         FlatSearchResponse result = nexusIndexer.searchFlat( new FlatSearchRequest( q, indexingContext ) );
144 
145         return result.getReturnedHitsCount();
146     }
147 
148     // ==
149 
150     public static class IndexUserThread
151         extends Thread
152     {
153         private final ConcurrentUseTest test;
154 
155         private final NexusIndexer nexusIndexer;
156 
157         private final IndexingContext searchIndexingContext;
158 
159         private final IndexingContext modifyIndexingContext;
160 
161         private boolean stopped = false;
162 
163         private int added = 0;
164 
165         private int deleted = 0;
166 
167         private int lastSearchHitCount = 0;
168 
169         private Throwable t;
170 
171         public IndexUserThread( final ConcurrentUseTest test, final NexusIndexer nexusIndexer,
172                                 final IndexingContext searchIndexingContext,
173                                 final IndexingContext modifyIndexingContext, ArtifactInfo artifactInfo )
174         {
175             this.test = test;
176 
177             this.nexusIndexer = nexusIndexer;
178 
179             this.searchIndexingContext = searchIndexingContext;
180 
181             this.modifyIndexingContext = modifyIndexingContext;
182         }
183 
184         public int getAdded()
185         {
186             return added;
187         }
188 
189         public int getDeleted()
190         {
191             return deleted;
192         }
193 
194         public boolean hadProblem()
195         {
196             return t != null;
197         }
198 
199         public int getLastSearchHitCount()
200         {
201             return lastSearchHitCount;
202         }
203 
204         public void stopThread()
205             throws IOException
206         {
207             this.modifyIndexingContext.commit();
208 
209             this.stopped = true;
210         }
211 
212         public void run()
213         {
214             while ( !stopped )
215             {
216                 if ( System.currentTimeMillis() % 5 == 0 )
217                 {
218                     try
219                     {
220                         test.addToIndex( nexusIndexer, modifyIndexingContext );
221 
222                         added++;
223                     }
224                     catch ( Throwable e )
225                     {
226                         t = e;
227 
228                         e.printStackTrace();
229 
230                         throw new IllegalStateException( "error", e );
231                     }
232                 }
233 
234                 if ( System.currentTimeMillis() % 11 == 0 )
235                 {
236                     try
237                     {
238                         // test.deleteFromIndex( nexusIndexer, modifyIndexingContext );
239                         // deleted++;
240                     }
241                     catch ( Throwable e )
242                     {
243                         t = e;
244 
245                         throw new IllegalStateException( "error", e );
246                     }
247                 }
248 
249                 try
250                 {
251                     lastSearchHitCount = test.readIndex( nexusIndexer, searchIndexingContext );
252                 }
253                 catch ( Throwable e )
254                 {
255                     t = e;
256 
257                     throw new IllegalStateException( "error", e );
258                 }
259             }
260         }
261     }
262 }