| package org.apache.maven.index; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.concurrent.atomic.AtomicInteger; |
| |
| import junit.framework.Assert; |
| |
| import org.apache.lucene.search.Query; |
| import org.apache.maven.index.context.DefaultIndexingContext; |
| import org.apache.maven.index.context.IndexingContext; |
| import org.apache.maven.index.expr.UserInputSearchExpression; |
| |
| public class ConcurrentUseTest |
| extends AbstractNexusIndexerTest |
| { |
| public static final int THREAD_COUNT = 10; |
| |
| protected File repo = new File( getBasedir(), "src/test/repo" ); |
| |
| @Override |
| protected void prepareNexusIndexer( NexusIndexer nexusIndexer ) |
| throws Exception |
| { |
| context = |
| nexusIndexer.addIndexingContext( "test-default", "test", repo, indexDir, null, null, DEFAULT_CREATORS ); |
| |
| assertNull( context.getTimestamp() ); // unknown upon creation |
| |
| nexusIndexer.scan( context ); |
| |
| assertNotNull( context.getTimestamp() ); |
| } |
| |
| protected IndexUserThread createThread( final ArtifactInfo ai ) |
| { |
| // we search and modify same context concurrently |
| return new IndexUserThread( this, nexusIndexer, context, context, ai ); |
| } |
| |
| public void testConcurrency() |
| throws Exception |
| { |
| IndexUserThread[] threads = new IndexUserThread[THREAD_COUNT]; |
| |
| ArtifactInfo ai = |
| new ArtifactInfo( "test-default", "org.apache.maven.indexer", "index-concurrent-artifact", "", null ); |
| |
| for ( int i = 0; i < THREAD_COUNT; i++ ) |
| { |
| threads[i] = createThread( ai ); |
| |
| threads[i].start(); |
| } |
| |
| Thread.sleep( 5000 ); |
| |
| boolean thereWereProblems = false; |
| |
| int totalAdded = 0; |
| |
| for ( int i = 0; i < THREAD_COUNT; i++ ) |
| { |
| threads[i].stopThread(); |
| |
| threads[i].join(); |
| |
| thereWereProblems = thereWereProblems || threads[i].hadProblem(); |
| |
| totalAdded += threads[i].getAdded(); |
| } |
| |
| Assert.assertFalse( "Not all thread did clean job!", thereWereProblems ); |
| |
| context.commit(); |
| |
| // sleep more than bottleWarmer does, to be sure commit and reopen happened |
| // BottleWarmer sleeps 1000 millis |
| Thread.sleep( 2000 ); |
| |
| // |
| |
| Query q = nexusIndexer.constructQuery( MAVEN.GROUP_ID, new UserInputSearchExpression( ai.groupId ) ); |
| |
| FlatSearchResponse result = nexusIndexer.searchFlat( new FlatSearchRequest( q, context ) ); |
| |
| Assert.assertEquals( "All added should be found after final commit!", totalAdded, result.getTotalHitsCount() ); |
| } |
| |
| // == |
| |
| private static final AtomicInteger versionSource = new AtomicInteger( 1 ); |
| |
| protected void addToIndex( final NexusIndexer nexusIndexer, final IndexingContext indexingContext ) |
| throws IOException |
| { |
| final ArtifactInfo artifactInfo = |
| new ArtifactInfo( "test-default", "org.apache.maven.indexer", "index-concurrent-artifact", "1." |
| + String.valueOf( versionSource.getAndIncrement() ), null ); |
| |
| final ArtifactContext ac = new ArtifactContext( null, null, null, artifactInfo, artifactInfo.calculateGav() ); |
| |
| nexusIndexer.addArtifactToIndex( ac, indexingContext ); |
| } |
| |
| protected void deleteFromIndex( final NexusIndexer nexusIndexer, final IndexingContext indexingContext ) |
| throws IOException |
| { |
| // TODO: delete some of those already added |
| // artifactInfo.version = "1." + String.valueOf( versionSource.getAndIncrement() ); |
| // |
| // ac = new ArtifactContext( null, null, null, artifactInfo, artifactInfo.calculateGav() ); |
| // |
| // nexusIndexer.deleteArtifactFromIndex( ac, indexingContext ); |
| // |
| // deleted++; |
| } |
| |
| protected int readIndex( final NexusIndexer nexusIndexer, final IndexingContext indexingContext ) |
| throws IOException |
| { |
| final Query q = |
| nexusIndexer.constructQuery( MAVEN.GROUP_ID, new UserInputSearchExpression( "org.apache.maven.indexer" ) ); |
| |
| FlatSearchResponse result = nexusIndexer.searchFlat( new FlatSearchRequest( q, indexingContext ) ); |
| |
| return result.getReturnedHitsCount(); |
| } |
| |
| // == |
| |
| public static class IndexUserThread |
| extends Thread |
| { |
| private final ConcurrentUseTest test; |
| |
| private final NexusIndexer nexusIndexer; |
| |
| private final IndexingContext searchIndexingContext; |
| |
| private final IndexingContext modifyIndexingContext; |
| |
| private boolean stopped = false; |
| |
| private int added = 0; |
| |
| private int deleted = 0; |
| |
| private int lastSearchHitCount = 0; |
| |
| private Throwable t; |
| |
| public IndexUserThread( final ConcurrentUseTest test, final NexusIndexer nexusIndexer, |
| final IndexingContext searchIndexingContext, |
| final IndexingContext modifyIndexingContext, ArtifactInfo artifactInfo ) |
| { |
| this.test = test; |
| |
| this.nexusIndexer = nexusIndexer; |
| |
| this.searchIndexingContext = searchIndexingContext; |
| |
| this.modifyIndexingContext = modifyIndexingContext; |
| } |
| |
| public int getAdded() |
| { |
| return added; |
| } |
| |
| public int getDeleted() |
| { |
| return deleted; |
| } |
| |
| public boolean hadProblem() |
| { |
| return t != null; |
| } |
| |
| public int getLastSearchHitCount() |
| { |
| return lastSearchHitCount; |
| } |
| |
| public void stopThread() |
| throws IOException |
| { |
| this.modifyIndexingContext.commit(); |
| |
| this.stopped = true; |
| } |
| |
| public void run() |
| { |
| while ( !stopped ) |
| { |
| if ( System.currentTimeMillis() % 5 == 0 ) |
| { |
| try |
| { |
| test.addToIndex( nexusIndexer, modifyIndexingContext ); |
| |
| added++; |
| } |
| catch ( Throwable e ) |
| { |
| t = e; |
| |
| e.printStackTrace(); |
| |
| throw new IllegalStateException( "error", e ); |
| } |
| } |
| |
| if ( System.currentTimeMillis() % 11 == 0 ) |
| { |
| try |
| { |
| // test.deleteFromIndex( nexusIndexer, modifyIndexingContext ); |
| // deleted++; |
| } |
| catch ( Throwable e ) |
| { |
| t = e; |
| |
| throw new IllegalStateException( "error", e ); |
| } |
| } |
| |
| try |
| { |
| lastSearchHitCount = test.readIndex( nexusIndexer, searchIndexingContext ); |
| } |
| catch ( Throwable e ) |
| { |
| t = e; |
| |
| throw new IllegalStateException( "error", e ); |
| } |
| } |
| } |
| } |
| } |