/*
* 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.
*/
package org.apache.lucene.index;
import java.io.IOException;
import org.apache.lucene.analysis.MockAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.ExitableDirectoryReader.ExitingReaderException;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.PrefixQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.LuceneTestCase;
import org.junit.Ignore;
/**
* Test that uses a default/lucene Implementation of {@link QueryTimeout}
* to exit out long running queries that take too long to iterate over Terms.
*/
public class TestExitableDirectoryReader extends LuceneTestCase {
private static class TestReader extends FilterLeafReader {
private static class TestFields extends FilterFields {
TestFields(Fields in) {
super(in);
}
@Override
public Terms terms(String field) throws IOException {
return new TestTerms(super.terms(field));
}
}
private static class TestTerms extends FilterTerms {
TestTerms(Terms in) {
super(in);
}
@Override
public TermsEnum iterator() throws IOException {
return new TestTermsEnum(super.iterator());
}
}
private static class TestTermsEnum extends FilterTermsEnum {
public TestTermsEnum(TermsEnum in) {
super(in);
}
/**
* Sleep between iterations to timeout things.
*/
@Override
public BytesRef next() throws IOException {
try {
// Sleep for 100ms before each .next() call.
Thread.sleep(100);
} catch (InterruptedException e) {
}
return in.next();
}
}
public TestReader(LeafReader reader) throws IOException {
super(reader);
}
@Override
public Fields fields() throws IOException {
return new TestFields(super.fields());
}
@Override
public CacheHelper getCoreCacheHelper() {
return in.getCoreCacheHelper();
}
@Override
public CacheHelper getReaderCacheHelper() {
return in.getReaderCacheHelper();
}
}
/**
* Tests timing out of TermsEnum iterations
* @throws Exception on error
*/
@Ignore("this test relies on wall clock time and sometimes false fails")
public void testExitableFilterIndexReader() throws Exception {
Directory directory = newDirectory();
IndexWriter writer = new IndexWriter(directory, newIndexWriterConfig(new MockAnalyzer(random())));
Document d1 = new Document();
d1.add(newTextField("default", "one two", Field.Store.YES));
writer.addDocument(d1);
Document d2 = new Document();
d2.add(newTextField("default", "one three", Field.Store.YES));
writer.addDocument(d2);
Document d3 = new Document();
d3.add(newTextField("default", "ones two four", Field.Store.YES));
writer.addDocument(d3);
writer.forceMerge(1);
writer.commit();
writer.close();
DirectoryReader directoryReader;
DirectoryReader exitableDirectoryReader;
IndexReader reader;
IndexSearcher searcher;
Query query = new PrefixQuery(new Term("default", "o"));
// Set a fairly high timeout value (1 second) and expect the query to complete in that time frame.
// Not checking the validity of the result, all we are bothered about in this test is the timing out.
directoryReader = DirectoryReader.open(directory);
exitableDirectoryReader = new ExitableDirectoryReader(directoryReader, new QueryTimeoutImpl(1000));
reader = new TestReader(getOnlyLeafReader(exitableDirectoryReader));
searcher = new IndexSearcher(reader);
searcher.search(query, 10);
reader.close();
// Set a really low timeout value (1 millisecond) and expect an Exception
directoryReader = DirectoryReader.open(directory);
exitableDirectoryReader = new ExitableDirectoryReader(directoryReader, new QueryTimeoutImpl(1));
reader = new TestReader(getOnlyLeafReader(exitableDirectoryReader));
IndexSearcher slowSearcher = new IndexSearcher(reader);
expectThrows(ExitingReaderException.class, () -> {
slowSearcher.search(query, 10);
});
reader.close();
// Set maximum time out and expect the query to complete.
// Not checking the validity of the result, all we are bothered about in this test is the timing out.
directoryReader = DirectoryReader.open(directory);
exitableDirectoryReader = new ExitableDirectoryReader(directoryReader, new QueryTimeoutImpl(Long.MAX_VALUE));
reader = new TestReader(getOnlyLeafReader(exitableDirectoryReader));
searcher = new IndexSearcher(reader);
searcher.search(query, 10);
reader.close();
// Set a negative time allowed and expect the query to complete (should disable timeouts)
// Not checking the validity of the result, all we are bothered about in this test is the timing out.
directoryReader = DirectoryReader.open(directory);
exitableDirectoryReader = new ExitableDirectoryReader(directoryReader, new QueryTimeoutImpl(-189034L));
reader = new TestReader(getOnlyLeafReader(exitableDirectoryReader));
searcher = new IndexSearcher(reader);
searcher.search(query, 10);
reader.close();
directory.close();
}
}