| package org.apache.lucene.facet.taxonomy; |
| |
| /* |
| * 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.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.util.IOUtils; |
| |
| /** |
| * Manages near-real-time reopen of both an IndexSearcher |
| * and a TaxonomyReader. |
| * |
| * <p><b>NOTE</b>: If you call {@link |
| * DirectoryTaxonomyWriter#replaceTaxonomy} then you must |
| * open a new {@code SearcherTaxonomyManager} afterwards. |
| */ |
| public class SearcherTaxonomyManager extends ReferenceManager<SearcherTaxonomyManager.SearcherAndTaxonomy> { |
| |
| /** Holds a matched pair of {@link IndexSearcher} and |
| * {@link TaxonomyReader} */ |
| public static class SearcherAndTaxonomy { |
| /** Point-in-time {@link IndexSearcher}. */ |
| public final IndexSearcher searcher; |
| |
| /** Matching point-in-time {@link DirectoryTaxonomyReader}. */ |
| public final DirectoryTaxonomyReader taxonomyReader; |
| |
| /** Create a SearcherAndTaxonomy */ |
| public SearcherAndTaxonomy(IndexSearcher searcher, DirectoryTaxonomyReader taxonomyReader) { |
| this.searcher = searcher; |
| this.taxonomyReader = taxonomyReader; |
| } |
| } |
| |
| private final SearcherFactory searcherFactory; |
| private final long taxoEpoch; |
| private final DirectoryTaxonomyWriter taxoWriter; |
| |
| /** 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; |
| this.taxoWriter = taxoWriter; |
| DirectoryTaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoWriter); |
| current = new SearcherAndTaxonomy(SearcherManager.getSearcher(searcherFactory, DirectoryReader.open(writer, applyAllDeletes)), |
| taxoReader); |
| taxoEpoch = taxoWriter.getTaxonomyEpoch(); |
| } |
| |
| @Override |
| protected void decRef(SearcherAndTaxonomy ref) throws IOException { |
| ref.searcher.getIndexReader().decRef(); |
| |
| // This decRef can fail, and then in theory we should |
| // tryIncRef the searcher to put back the ref count |
| // ... but 1) the below decRef should only fail because |
| // it decRef'd to 0 and closed and hit some IOException |
| // during close, in which case 2) very likely the |
| // searcher was also just closed by the above decRef and |
| // a tryIncRef would fail: |
| 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 { |
| DirectoryTaxonomyReader tr = TaxonomyReader.openIfChanged(ref.taxonomyReader); |
| if (tr == null) { |
| ref.taxonomyReader.incRef(); |
| tr = ref.taxonomyReader; |
| } else if (taxoWriter.getTaxonomyEpoch() != taxoEpoch) { |
| IOUtils.close(newReader, tr); |
| throw new IllegalStateException("DirectoryTaxonomyWriter.replaceTaxonomy was called, which is not allowed when using SearcherTaxonomyManager"); |
| } |
| |
| return new SearcherAndTaxonomy(SearcherManager.getSearcher(searcherFactory, newReader), tr); |
| } |
| } |
| } |