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 org.apache.lucene.search.Query;
27  import org.apache.maven.index.context.IndexingContext;
28  import org.apache.maven.index.expr.UserInputSearchExpression;
29  import org.junit.Test;
30  
31  import static org.junit.Assert.assertEquals;
32  import static org.junit.Assert.assertFalse;
33  import static org.junit.Assert.assertNotNull;
34  import static org.junit.Assert.assertNull;
35  
36  public class ConcurrentUseTest
37      extends AbstractNexusIndexerTest
38  {
39      public static final int THREAD_COUNT = 10;
40  
41      protected File repo = new File( getBasedir(), "src/test/repo" );
42  
43      @Override
44      protected void prepareNexusIndexer( NexusIndexer nexusIndexer )
45          throws Exception
46      {
47          context =
48              nexusIndexer.addIndexingContext( "test-default", "test", repo, indexDir, null, null, DEFAULT_CREATORS );
49  
50          assertNull( context.getTimestamp() ); // unknown upon creation
51  
52          nexusIndexer.scan( context );
53  
54          assertNotNull( context.getTimestamp() );
55      }
56  
57      protected IndexUserThread createThread( final ArtifactInfo ai )
58      {
59          // we search and modify same context concurrently
60          return new IndexUserThread( this, nexusIndexer, context, context, ai );
61      }
62  
63      @Test
64      public void testConcurrency()
65          throws Exception
66      {
67          IndexUserThread[] threads = new IndexUserThread[THREAD_COUNT];
68  
69          ArtifactInfo ai =
70              new ArtifactInfo( "test-default", "org.apache.maven.indexer", "index-concurrent-artifact", "", null, "jar" );
71  
72          for ( int i = 0; i < THREAD_COUNT; i++ )
73          {
74              threads[i] = createThread( ai );
75  
76              threads[i].start();
77          }
78  
79          Thread.sleep( 5000 );
80  
81          boolean thereWereProblems = false;
82  
83          int totalAdded = 0;
84  
85          for ( int i = 0; i < THREAD_COUNT; i++ )
86          {
87              threads[i].stopThread();
88  
89              threads[i].join();
90  
91              thereWereProblems = thereWereProblems || threads[i].hadProblem();
92  
93              totalAdded += threads[i].getAdded();
94          }
95  
96          assertFalse( "Not all thread did clean job!", thereWereProblems );
97  
98          context.commit();
99  
100         // sleep more than bottleWarmer does, to be sure commit and reopen happened
101         // BottleWarmer sleeps 1000 millis
102         Thread.sleep( 2000 );
103 
104         //
105 
106         Query q = nexusIndexer.constructQuery( MAVEN.GROUP_ID, new UserInputSearchExpression( ai.getGroupId() ) );
107 
108         FlatSearchResponse result = nexusIndexer.searchFlat( new FlatSearchRequest( q, context ) );
109 
110         assertEquals( "All added should be found after final commit!", totalAdded, result.getTotalHitsCount() );
111     }
112 
113     // ==
114 
115     private static final AtomicInteger versionSource = new AtomicInteger( 1 );
116 
117     protected void addToIndex( final NexusIndexer nexusIndexer, final IndexingContext indexingContext )
118         throws IOException
119     {
120         final ArtifactInfo artifactInfo =
121             new ArtifactInfo( "test-default", "org.apache.maven.indexer", "index-concurrent-artifact", "1."
122                 + versionSource.getAndIncrement(), null , "jar");
123 
124         final ArtifactContext ac = new ArtifactContext( null, null, null, artifactInfo, artifactInfo.calculateGav() );
125 
126         nexusIndexer.addArtifactToIndex( ac, indexingContext );
127     }
128 
129     protected void deleteFromIndex( final NexusIndexer nexusIndexer, final IndexingContext indexingContext )
130         throws IOException
131     {
132         // TODO: delete some of those already added
133         // artifactInfo.version = "1." + String.valueOf( versionSource.getAndIncrement() );
134         //
135         // ac = new ArtifactContext( null, null, null, artifactInfo, artifactInfo.calculateGav() );
136         //
137         // nexusIndexer.deleteArtifactFromIndex( ac, indexingContext );
138         //
139         // deleted++;
140     }
141 
142     protected int readIndex( final NexusIndexer nexusIndexer, final IndexingContext indexingContext )
143         throws IOException
144     {
145         final Query q =
146             nexusIndexer.constructQuery( MAVEN.GROUP_ID, new UserInputSearchExpression( "org.apache.maven.indexer" ) );
147 
148         FlatSearchResponse result = nexusIndexer.searchFlat( new FlatSearchRequest( q, indexingContext ) );
149 
150         return result.getReturnedHitsCount();
151     }
152 
153     // ==
154 
155     public static class IndexUserThread
156         extends Thread
157     {
158         private final ConcurrentUseTest test;
159 
160         private final NexusIndexer nexusIndexer;
161 
162         private final IndexingContext searchIndexingContext;
163 
164         private final IndexingContext modifyIndexingContext;
165 
166         private boolean stopped = false;
167 
168         private int added = 0;
169 
170         private int deleted = 0;
171 
172         private int lastSearchHitCount = 0;
173 
174         private Throwable t;
175 
176         public IndexUserThread( final ConcurrentUseTest test, final NexusIndexer nexusIndexer,
177                                 final IndexingContext searchIndexingContext,
178                                 final IndexingContext modifyIndexingContext, ArtifactInfo artifactInfo )
179         {
180             this.test = test;
181 
182             this.nexusIndexer = nexusIndexer;
183 
184             this.searchIndexingContext = searchIndexingContext;
185 
186             this.modifyIndexingContext = modifyIndexingContext;
187         }
188 
189         public int getAdded()
190         {
191             return added;
192         }
193 
194         public int getDeleted()
195         {
196             return deleted;
197         }
198 
199         public boolean hadProblem()
200         {
201             return t != null;
202         }
203 
204         public int getLastSearchHitCount()
205         {
206             return lastSearchHitCount;
207         }
208 
209         public void stopThread()
210             throws IOException
211         {
212             this.modifyIndexingContext.commit();
213 
214             this.stopped = true;
215         }
216 
217         public void run()
218         {
219             while ( !stopped )
220             {
221                 if ( System.currentTimeMillis() % 5 == 0 )
222                 {
223                     try
224                     {
225                         test.addToIndex( nexusIndexer, modifyIndexingContext );
226 
227                         added++;
228                     }
229                     catch ( Throwable e )
230                     {
231                         t = e;
232 
233                         e.printStackTrace();
234 
235                         throw new IllegalStateException( "error", e );
236                     }
237                 }
238 
239                 if ( System.currentTimeMillis() % 11 == 0 )
240                 {
241                     try
242                     {
243                         // test.deleteFromIndex( nexusIndexer, modifyIndexingContext );
244                         // deleted++;
245                     }
246                     catch ( Throwable e )
247                     {
248                         t = e;
249 
250                         throw new IllegalStateException( "error", e );
251                     }
252                 }
253 
254                 try
255                 {
256                     lastSearchHitCount = test.readIndex( nexusIndexer, searchIndexingContext );
257                 }
258                 catch ( Throwable e )
259                 {
260                     t = e;
261 
262                     throw new IllegalStateException( "error", e );
263                 }
264             }
265         }
266     }
267 }