blob: 8a5f82d66412f1742502de83b37608529b4e1da0 [file] [log] [blame]
// Lucene version compatibility level 4.8.1
using Lucene.Net.Search;
using System;
namespace Lucene.Net.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.
*/
using Directory = Lucene.Net.Store.Directory;
using DirectoryReader = Lucene.Net.Index.DirectoryReader;
using DirectoryTaxonomyReader = Lucene.Net.Facet.Taxonomy.Directory.DirectoryTaxonomyReader;
using DirectoryTaxonomyWriter = Lucene.Net.Facet.Taxonomy.Directory.DirectoryTaxonomyWriter;
using IndexReader = Lucene.Net.Index.IndexReader;
using IndexSearcher = Lucene.Net.Search.IndexSearcher;
using IndexWriter = Lucene.Net.Index.IndexWriter;
using IOUtils = Lucene.Net.Util.IOUtils;
using SearcherFactory = Lucene.Net.Search.SearcherFactory;
using SearcherManager = Lucene.Net.Search.SearcherManager;
/// <summary>
/// Manages near-real-time reopen of both an <see cref="IndexSearcher"/>
/// and a <see cref="TaxonomyReader"/>.
///
/// <para>
/// <b>NOTE</b>: If you call <see cref="DirectoryTaxonomyWriter.ReplaceTaxonomy"/>
/// then you must open a new <see cref="SearcherTaxonomyManager"/> afterwards.
/// </para>
/// </summary>
public class SearcherTaxonomyManager : ReferenceManager<SearcherTaxonomyManager.SearcherAndTaxonomy>
{
/// <summary>
/// Holds a matched pair of <see cref="IndexSearcher"/> and
/// <see cref="Taxonomy.TaxonomyReader"/>
/// </summary>
public class SearcherAndTaxonomy
{
/// <summary>
/// Point-in-time <see cref="IndexSearcher"/>.
/// </summary>
public IndexSearcher Searcher { get; private set; }
/// <summary>
/// Matching point-in-time <see cref="DirectoryTaxonomyReader"/>.
/// </summary>
public DirectoryTaxonomyReader TaxonomyReader { get; private set; }
/// <summary>
/// Create a <see cref="SearcherAndTaxonomy"/>
/// </summary>
public SearcherAndTaxonomy(IndexSearcher searcher, DirectoryTaxonomyReader taxonomyReader)
{
this.Searcher = searcher;
this.TaxonomyReader = taxonomyReader;
}
}
private readonly SearcherFactory searcherFactory;
private readonly long taxoEpoch;
private readonly DirectoryTaxonomyWriter taxoWriter;
/// <summary>
/// Creates near-real-time searcher and taxonomy reader
/// from the corresponding writers.
/// </summary>
public SearcherTaxonomyManager(IndexWriter writer, bool applyAllDeletes,
SearcherFactory searcherFactory, DirectoryTaxonomyWriter taxoWriter)
{
if (searcherFactory == null)
{
searcherFactory = new SearcherFactory();
}
this.searcherFactory = searcherFactory;
this.taxoWriter = taxoWriter;
var taxoReader = new DirectoryTaxonomyReader(taxoWriter);
Current = new SearcherAndTaxonomy(SearcherManager.GetSearcher(
searcherFactory, DirectoryReader.Open(writer, applyAllDeletes)), taxoReader);
this.taxoEpoch = taxoWriter.TaxonomyEpoch;
}
/// <summary>
/// Creates search and taxonomy readers over the corresponding directories.
///
/// <para>
/// <b>NOTE:</b> you should only use this constructor if you commit and call
/// <see cref="Search.ReferenceManager{G}.MaybeRefresh()"/> (on the <see cref="Index.ReaderManager"/>) in the same thread. Otherwise it could lead to an
/// unsync'd <see cref="IndexSearcher"/> and <see cref="TaxonomyReader"/> pair.
/// </para>
/// </summary>
public SearcherTaxonomyManager(Store.Directory indexDir, Store.Directory taxoDir, SearcherFactory searcherFactory)
{
if (searcherFactory == null)
{
searcherFactory = new SearcherFactory();
}
this.searcherFactory = searcherFactory;
var taxoReader = new DirectoryTaxonomyReader(taxoDir);
Current = new SearcherAndTaxonomy(SearcherManager.GetSearcher(
searcherFactory, DirectoryReader.Open(indexDir)), taxoReader);
this.taxoWriter = null;
taxoEpoch = -1;
}
protected override void DecRef(SearcherAndTaxonomy @ref)
{
@ref.Searcher.IndexReader.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();
}
protected override bool TryIncRef(SearcherAndTaxonomy @ref)
{
if (@ref.Searcher.IndexReader.TryIncRef())
{
if (@ref.TaxonomyReader.TryIncRef())
{
return true;
}
else
{
@ref.Searcher.IndexReader.DecRef();
}
}
return false;
}
protected override SearcherAndTaxonomy RefreshIfNeeded(SearcherAndTaxonomy @ref)
{
// Must re-open searcher first, otherwise we may get a
// new reader that references ords not yet known to the
// taxonomy reader:
IndexReader r = @ref.Searcher.IndexReader;
IndexReader newReader = DirectoryReader.OpenIfChanged((DirectoryReader)r);
if (newReader == null)
{
return null;
}
else
{
var tr = TaxonomyReader.OpenIfChanged(@ref.TaxonomyReader);
if (tr == null)
{
@ref.TaxonomyReader.IncRef();
tr = @ref.TaxonomyReader;
}
else if (taxoWriter != null && taxoWriter.TaxonomyEpoch != taxoEpoch)
{
IOUtils.Dispose(newReader, tr);
throw new InvalidOperationException("DirectoryTaxonomyWriter.replaceTaxonomy was called, which is not allowed when using SearcherTaxonomyManager");
}
return new SearcherAndTaxonomy(SearcherManager.GetSearcher(searcherFactory, newReader), tr);
}
}
protected override int GetRefCount(SearcherAndTaxonomy reference)
{
return reference.Searcher.IndexReader.RefCount;
}
}
}