blob: c4169ee14340ea6cd6cc8ed643209b38613225b4 [file] [log] [blame]
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);
}
}
}