diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index bbd06194c52..d031b881055 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -225,6 +225,10 @@ Bug Fixes * LUCENE-5103: A join on A single-valued field with deleted docs scored too few docs. (David Smiley) +* LUCENE-5090: Detect mismatched readers passed to + SortedSetDocValuesReaderState and SortedSetDocValuesAccumulator. + (Robert Muir, Mike McCandless) + Optimizations * LUCENE-4936: Improve numeric doc values compression in case all values share diff --git a/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesAccumulator.java b/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesAccumulator.java index 99c65e529ff..108be03f5ca 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesAccumulator.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesAccumulator.java @@ -35,9 +35,11 @@ import org.apache.lucene.facet.search.FacetsAccumulator; import org.apache.lucene.facet.search.FacetsAggregator; import org.apache.lucene.facet.search.FacetsCollector.MatchingDocs; import org.apache.lucene.facet.taxonomy.CategoryPath; +import org.apache.lucene.index.AtomicReader; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.MultiDocValues.MultiSortedSetDocValues; import org.apache.lucene.index.MultiDocValues; +import org.apache.lucene.index.ReaderUtil; import org.apache.lucene.index.SortedSetDocValues; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.PriorityQueue; @@ -57,7 +59,7 @@ public class SortedSetDocValuesAccumulator extends FacetsAccumulator { final String field; public SortedSetDocValuesAccumulator(FacetSearchParams fsp, SortedSetDocValuesReaderState state) throws IOException { - super(fsp, null, null, new FacetArrays((int) state.getDocValues().getValueCount())); + super(fsp, null, null, new FacetArrays(state.getSize())); this.state = state; this.field = state.getField(); dv = state.getDocValues(); @@ -90,13 +92,23 @@ public class SortedSetDocValuesAccumulator extends FacetsAccumulator { @Override public void aggregate(MatchingDocs matchingDocs, CategoryListParams clp, FacetArrays facetArrays) throws IOException { - SortedSetDocValues segValues = matchingDocs.context.reader().getSortedSetDocValues(field); + AtomicReader reader = matchingDocs.context.reader(); + + // LUCENE-5090: make sure the provided reader context "matches" + // the top-level reader passed to the + // SortedSetDocValuesReaderState, else cryptic + // AIOOBE can happen: + if (ReaderUtil.getTopLevelContext(matchingDocs.context).reader() != state.origReader) { + throw new IllegalStateException("the SortedSetDocValuesReaderState provided to this class does not match the reader being searched; you must create a new SortedSetDocValuesReaderState every time you open a new IndexReader"); + } + + SortedSetDocValues segValues = reader.getSortedSetDocValues(field); if (segValues == null) { return; } final int[] counts = facetArrays.getIntArray(); - final int maxDoc = matchingDocs.context.reader().maxDoc(); + final int maxDoc = reader.maxDoc(); assert maxDoc == matchingDocs.bits.length(); if (dv instanceof MultiSortedSetDocValues) { diff --git a/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesReaderState.java b/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesReaderState.java index 819c3840094..7d9c6c7a646 100644 --- a/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesReaderState.java +++ b/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesReaderState.java @@ -51,6 +51,7 @@ public final class SortedSetDocValuesReaderState { private final String field; private final AtomicReader topReader; private final int valueCount; + final IndexReader origReader; final char separator; final String separatorRegex; @@ -91,6 +92,7 @@ public final class SortedSetDocValuesReaderState { this.field = fip.getCategoryListParams(null).field + FACET_FIELD_EXTENSION; this.separator = fip.getFacetDelimChar(); this.separatorRegex = Pattern.quote(Character.toString(separator)); + this.origReader = reader; // We need this to create thread-safe MultiSortedSetDV // per collector: diff --git a/lucene/facet/src/test/org/apache/lucene/facet/sortedset/TestSortedSetDocValuesFacets.java b/lucene/facet/src/test/org/apache/lucene/facet/sortedset/TestSortedSetDocValuesFacets.java index 7d2ee2e597d..55db5ad723b 100644 --- a/lucene/facet/src/test/org/apache/lucene/facet/sortedset/TestSortedSetDocValuesFacets.java +++ b/lucene/facet/src/test/org/apache/lucene/facet/sortedset/TestSortedSetDocValuesFacets.java @@ -33,6 +33,7 @@ import org.apache.lucene.facet.search.FacetRequest; import org.apache.lucene.facet.search.FacetResult; import org.apache.lucene.facet.search.FacetsCollector; import org.apache.lucene.facet.taxonomy.CategoryPath; +import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MatchAllDocsQuery; @@ -145,4 +146,51 @@ public class TestSortedSetDocValuesFacets extends FacetTestCase { searcher.getIndexReader().close(); dir.close(); } + + // LUCENE-5090 + public void testStaleState() throws Exception { + assumeTrue("Test requires SortedSetDV support", defaultCodecSupportsSortedSet()); + Directory dir = newDirectory(); + RandomIndexWriter writer = new RandomIndexWriter(random(), dir); + + SortedSetDocValuesFacetFields dvFields = new SortedSetDocValuesFacetFields(); + + Document doc = new Document(); + dvFields.addFields(doc, Collections.singletonList(new CategoryPath("a", "foo"))); + writer.addDocument(doc); + + IndexReader r = writer.getReader(); + SortedSetDocValuesReaderState state = new SortedSetDocValuesReaderState(r); + + doc = new Document(); + dvFields.addFields(doc, Collections.singletonList(new CategoryPath("a", "bar"))); + writer.addDocument(doc); + + doc = new Document(); + dvFields.addFields(doc, Collections.singletonList(new CategoryPath("a", "baz"))); + writer.addDocument(doc); + + IndexSearcher searcher = newSearcher(writer.getReader()); + + List requests = new ArrayList(); + requests.add(new CountFacetRequest(new CategoryPath("a"), 10)); + + FacetSearchParams fsp = new FacetSearchParams(requests); + + FacetsCollector c = FacetsCollector.create(new SortedSetDocValuesAccumulator(fsp, state)); + + searcher.search(new MatchAllDocsQuery(), c); + + try { + c.getFacetResults(); + fail("did not hit expected exception"); + } catch (IllegalStateException ise) { + // expected + } + + r.close(); + writer.close(); + searcher.getIndexReader().close(); + dir.close(); + } }