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