Index: src/test/org/apache/lucene/search/TestSearchDelete.java =================================================================== --- src/test/org/apache/lucene/search/TestSearchDelete.java (revision 0) +++ src/test/org/apache/lucene/search/TestSearchDelete.java (revision 0) @@ -0,0 +1,146 @@ +package org.apache.lucene.search; + +/** + * 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.IOException; +import java.util.ConcurrentModificationException; + +import junit.framework.TestCase; + +import org.apache.lucene.analysis.WhitespaceAnalyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.document.Field; +import org.apache.lucene.index.CorruptIndexException; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.StaleReaderException; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.Hits; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.Query; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.LockObtainFailedException; +import org.apache.lucene.store.RAMDirectory; + +/** + * Test deletions during search. + * + * See {@link http://issues.apache.org/jira/browse/LUCENE-1096}. + */ +public class TestSearchDelete extends TestCase { + + private static boolean VERBOSE = false; + private static final String TEXT_FIELD = "text"; + private static final int N = 409; + + private static Directory directory; + + public void setUp() throws Exception { + // Create an index writer. + directory = new RAMDirectory(); + IndexWriter writer = new IndexWriter(directory, new WhitespaceAnalyzer(), true); + for (int i=0; i0 && i%k==0)) { + int id = hits.id(i); + Document doc = hits.doc(id); + log("Deleting hit "+i+" - doc "+doc+" with id "+id); + reader.deleteDocument(id); + } + for (int j = 0; jmin has been retrieved. @@ -72,6 +89,7 @@ int n = min * 2; // double # retrieved TopDocs topDocs = (sort == null) ? searcher.search(weight, filter, n) : searcher.search(weight, filter, n, sort); + length = topDocs.totalHits; ScoreDoc[] scoreDocs = topDocs.scoreDocs; @@ -81,8 +99,28 @@ scoreNorm = 1.0f / topDocs.getMaxScore(); } + int start = hitDocs.size(); + int nDeletedHits = 0; + + // any deletions since start? + if (nDeletedAtStart < 0 || countDeleted(searcher) > nDeletedAtStart) { + // either we cannot count deletions, or some "previously valid hits" might have been deleted, so find exact start point + int i2 = 0; + for (int i1=0; i1= length) { + if (n >= lengthAtStart) { throw new IndexOutOfBoundsException("Not a valid hit number: " + n); } @@ -154,6 +192,10 @@ getMoreDocs(n); } + if (n >= length) { + throw new ConcurrentModificationException("Not a valid hit number: " + n); + } + return (HitDoc) hitDocs.elementAt(n); }