Index: lucene/test-framework/src/java/org/apache/lucene/search/ShardSearchingTestBase.java =================================================================== --- lucene/test-framework/src/java/org/apache/lucene/search/ShardSearchingTestBase.java (revision 1465787) +++ lucene/test-framework/src/java/org/apache/lucene/search/ShardSearchingTestBase.java (working copy) @@ -448,7 +448,7 @@ currentNodeVersions = new long[numNodes]; } - public void initSearcher(long[] nodeVersions) { + public void initSearcher(long[] nodeVersions) throws IOException { assert currentShardSearcher == null; System.arraycopy(nodeVersions, 0, currentNodeVersions, 0, currentNodeVersions.length); currentShardSearcher = new ShardIndexSearcher(currentNodeVersions.clone(), Index: lucene/facet/src/test/org/apache/lucene/facet/search/TestSearcherTaxonomyManager.java =================================================================== --- lucene/facet/src/test/org/apache/lucene/facet/search/TestSearcherTaxonomyManager.java (revision 0) +++ lucene/facet/src/test/org/apache/lucene/facet/search/TestSearcherTaxonomyManager.java (working copy) @@ -0,0 +1,179 @@ +package org.apache.lucene.facet.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.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.lucene.analysis.MockAnalyzer; +import org.apache.lucene.document.Document; +import org.apache.lucene.facet.index.FacetFields; +import org.apache.lucene.facet.params.FacetIndexingParams; +import org.apache.lucene.facet.params.FacetSearchParams; +import org.apache.lucene.facet.search.SearcherTaxonomyManager.SearcherAndTaxonomy; +import org.apache.lucene.facet.taxonomy.CategoryPath; +import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.search.MatchAllDocsQuery; +import org.apache.lucene.store.Directory; +import org.apache.lucene.util.LuceneTestCase; +import org.apache.lucene.util._TestUtil; + +public class TestSearcherTaxonomyManager extends LuceneTestCase { + public void test() throws Exception { + Directory dir = newFSDirectory(_TestUtil.getTempDir("TestSearcherTaxonomyReader.index")); + Directory taxoDir = newFSDirectory(_TestUtil.getTempDir("TestSearcherTaxonomyReader.taxoIndex")); + final IndexWriter w = new IndexWriter(dir, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random()))); + final DirectoryTaxonomyWriter tw = new DirectoryTaxonomyWriter(taxoDir); + final FacetFields facetFields = new FacetFields(tw); + final AtomicBoolean stop = new AtomicBoolean(); + + Thread indexer = new Thread() { + @Override + public void run() { + Set seen = new HashSet(); + List paths = new ArrayList(); + while (!stop.get()) { + Document doc = new Document(); + List docPaths = new ArrayList(); + int numPaths = _TestUtil.nextInt(random(), 1, 5); + for(int i=0;i results = fc.getFacetResults(); + assertEquals(1, results.size()); + //if (VERBOSE) { + //System.out.println("TEST: facets=" + FacetTestUtils.toSimpleString(results.get(0))); + //} + } finally { + mgr.release(pair); + } + } + } finally { + stop.set(true); + indexer.join(); + reopener.join(); + } + + if (VERBOSE) { + System.out.println("TEST: now stop"); + } + + mgr.close(); + w.close(); + tw.close(); + dir.close(); + taxoDir.close(); + } +} Property changes on: lucene/facet/src/test/org/apache/lucene/facet/search/TestSearcherTaxonomyManager.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: lucene/facet/src/java/org/apache/lucene/facet/search/SearcherTaxonomyManager.java =================================================================== --- lucene/facet/src/java/org/apache/lucene/facet/search/SearcherTaxonomyManager.java (revision 0) +++ lucene/facet/src/java/org/apache/lucene/facet/search/SearcherTaxonomyManager.java (working copy) @@ -0,0 +1,114 @@ +package org.apache.lucene.facet.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 org.apache.lucene.facet.taxonomy.TaxonomyReader; +import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader; +import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter; +import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.search.IndexSearcher; +import org.apache.lucene.search.ReferenceManager; +import org.apache.lucene.search.SearcherFactory; +import org.apache.lucene.search.SearcherManager; +import org.apache.lucene.store.Directory; + +/** + * Manages reopens of both an IndexSearcher and a TaxonomyReader. + */ +public class SearcherTaxonomyManager extends ReferenceManager { + + /** Holds a matched pair of {@link IndexSearcher} and + * {@link TaxonomyReader} */ + public static class SearcherAndTaxonomy { + public final IndexSearcher searcher; + public final DirectoryTaxonomyReader taxonomyReader; + + SearcherAndTaxonomy(IndexSearcher searcher, DirectoryTaxonomyReader taxonomyReader) { + this.searcher = searcher; + this.taxonomyReader = taxonomyReader; + } + } + + private final SearcherFactory searcherFactory; + + /** Creates near-real-time searcher and taxonomy reader + * from the corresponding writers. */ + public SearcherTaxonomyManager(IndexWriter writer, boolean applyAllDeletes, SearcherFactory searcherFactory, DirectoryTaxonomyWriter taxoWriter) throws IOException { + if (searcherFactory == null) { + searcherFactory = new SearcherFactory(); + } + this.searcherFactory = searcherFactory; + IndexSearcher searcher = SearcherManager.getSearcher(searcherFactory, DirectoryReader.open(writer, applyAllDeletes)); + DirectoryTaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoWriter); + current = new SearcherAndTaxonomy(searcher, taxoReader); + } + + /** Creates non-near-real-time searcher and taxonomy reader + * from the corresponding directories. */ + public SearcherTaxonomyManager(Directory searcherDirectory, SearcherFactory searcherFactory, Directory taxonomyDirectory) throws IOException { + if (searcherFactory == null) { + searcherFactory = new SearcherFactory(); + } + this.searcherFactory = searcherFactory; + IndexSearcher searcher = SearcherManager.getSearcher(searcherFactory, DirectoryReader.open(searcherDirectory)); + DirectoryTaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxonomyDirectory); + current = new SearcherAndTaxonomy(searcher, taxoReader); + } + + @Override + protected void decRef(SearcherAndTaxonomy ref) throws IOException { + ref.searcher.getIndexReader().decRef(); + ref.taxonomyReader.decRef(); + } + + @Override + protected boolean tryIncRef(SearcherAndTaxonomy ref) throws IOException { + if (ref.searcher.getIndexReader().tryIncRef()) { + if (ref.taxonomyReader.tryIncRef()) { + return true; + } else { + ref.searcher.getIndexReader().decRef(); + } + } + return false; + } + + @Override + protected SearcherAndTaxonomy refreshIfNeeded(SearcherAndTaxonomy ref) throws IOException { + // Must re-open searcher first, otherwise we may get a + // new reader that references ords not yet known to the + // taxonomy reader: + final IndexReader r = ref.searcher.getIndexReader(); + final IndexReader newReader = DirectoryReader.openIfChanged((DirectoryReader) r); + if (newReader == null) { + return null; + } else { + IndexSearcher searcher = SearcherManager.getSearcher(searcherFactory, newReader); + DirectoryTaxonomyReader tr = TaxonomyReader.openIfChanged(ref.taxonomyReader); + if (tr == null) { + ref.taxonomyReader.incRef(); + tr = ref.taxonomyReader; + } + return new SearcherAndTaxonomy(searcher, tr); + } + } +} Property changes on: lucene/facet/src/java/org/apache/lucene/facet/search/SearcherTaxonomyManager.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: lucene/facet/src/java/org/apache/lucene/facet/search/FastCountingFacetsAggregator.java =================================================================== --- lucene/facet/src/java/org/apache/lucene/facet/search/FastCountingFacetsAggregator.java (revision 1465787) +++ lucene/facet/src/java/org/apache/lucene/facet/search/FastCountingFacetsAggregator.java (working copy) @@ -83,6 +83,7 @@ byte b = buf.bytes[offset++]; if (b >= 0) { prev = ord = ((ord << 7) | b) + prev; + assert ord < counts.length: "ord=" + ord + " vs maxOrd=" + counts.length; ++counts[ord]; ord = 0; } else { Index: lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyReader.java =================================================================== --- lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyReader.java (revision 1465787) +++ lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyReader.java (working copy) @@ -246,4 +246,16 @@ refCount.incrementAndGet(); } + /** Expert: increments the refCount of this TaxonomyReader + * instance only if it has not been closed yet. Returns + * true on success. */ + public final boolean tryIncRef() { + int count; + while ((count = refCount.get()) > 0) { + if (refCount.compareAndSet(count, count+1)) { + return true; + } + } + return false; + } } Index: lucene/core/src/java/org/apache/lucene/search/SearcherManager.java =================================================================== --- lucene/core/src/java/org/apache/lucene/search/SearcherManager.java (revision 1465787) +++ lucene/core/src/java/org/apache/lucene/search/SearcherManager.java (working copy) @@ -144,8 +144,11 @@ } } - // NOTE: decRefs incoming reader on throwing an exception - static IndexSearcher getSearcher(SearcherFactory searcherFactory, IndexReader reader) throws IOException { + /** Expert: creates a searcher from the provided {@link + * IndexReader} using the provided {@link + * SearcherFactory}. NOTE: this decRefs incoming reader + * on throwing an exception. */ + public static IndexSearcher getSearcher(SearcherFactory searcherFactory, IndexReader reader) throws IOException { boolean success = false; final IndexSearcher searcher; try { Index: lucene/core/src/java/org/apache/lucene/search/ReferenceManager.java =================================================================== --- lucene/core/src/java/org/apache/lucene/search/ReferenceManager.java (revision 1465787) +++ lucene/core/src/java/org/apache/lucene/search/ReferenceManager.java (working copy) @@ -81,7 +81,7 @@ * the operation was successful. * @throws AlreadyClosedException if the reference manager has been {@link #close() closed}. */ - protected abstract boolean tryIncRef(G reference); + protected abstract boolean tryIncRef(G reference) throws IOException; /** * Obtain the current reference. You must match every call to acquire with one @@ -90,7 +90,7 @@ * released. * @throws AlreadyClosedException if the reference manager has been {@link #close() closed}. */ - public final G acquire() { + public final G acquire() throws IOException { G ref; do { if ((ref = current) == null) {