Использование потока Lucene.Net -безопасно для веб-приложения asp.net

Поэтому я провел небольшое исследование, чтобы найти лучший способ реализации поиска и записи по индексу Lucene.Net из веб-приложения. Я изложил следующие требования:

  • Необходимо разрешить одновременный поиск и доступ к индексу (запросы выполняются параллельно)
  • будет несколько индексов
  • иметь поиск по индексу полностью -до -даты («реальное -время» )НЕ является требованием
  • запускать задания для обновления индексов с определенной частотой (частота разная для каждого индекса)
  • очевидно, хотел бы сделать все это таким образом, чтобы следовать «лучшим практикам» lucene и иметь хорошую производительность и масштабирование

. Я нашел несколько полезных ресурсов и пару хороших вопросов здесь по SO, например этот

Следуя этому сообщению в качестве руководства, я решил попробовать одноэлементный шаблон с параллельным словарем оболочки, созданной для управления индексом.

Чтобы упростить задачу, я представлю, что управляю только одним индексом, и в этом случае оболочка может стать синглтоном. В итоге это выглядит так:

public sealed class SingleIndexManager
{
    private const string IndexDirectory = "C:\\IndexDirectory\\";
    private const string IndexName = "test-index";
    private static readonly Version _version = Version.LUCENE_29;

    #region Singleton Behavior
    private static volatile SingleIndexManager _instance;
    private static object syncRoot = new Object();

    public static SingleIndexManager Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (syncRoot)
                {
                    if (_instance == null)
                        _instance = new SingleIndexManager();
                }
            }

            return _instance;
        }
    }
    #endregion

    private IndexWriter _writer;
    private IndexSearcher _searcher;

    private int _activeSearches = 0;
    private int _activeWrites = 0;

    private SingleIndexManager()
    {
        lock(syncRoot)
        {
            _writer = CreateWriter(); //hidden for sake of brevity
            _searcher = new IndexSearcher(_writer.GetReader());
        }
    }

    public List Search(Func> searchMethod)
    {
        lock(syncRoot)
        {
            if(_searcher != null && !_searcher.GetIndexReader().IsCurrent() && _activeSearches == 0)
            {
                _searcher.Close();
                _searcher = null;
            }
            if(_searcher == null)
            {
                _searcher = new IndexSearcher((_writer ?? (_writer = CreateWriter())).GetReader());
            }
        }
        List results;
        Interlocked.Increment(ref _activeSearches);
        try
        {
            results = searchMethod(_searcher);
        } 
        finally
        {
            Interlocked.Decrement(ref _activeSearches);
        }
        return results;
    }

    public void Write(List docs)
    {
        lock(syncRoot)
        {
            if(_writer == null)
            {
                _writer = CreateWriter();
            }
        }
        try
        {
            Interlocked.Increment(ref _activeWrites);
            foreach (Document document in docs)
            {
                _writer.AddDocument(document, new StandardAnalyzer(_version));
            }

        } 
        finally
        {
            lock(syncRoot)
            {
                int writers = Interlocked.Decrement(ref _activeWrites);
                if(writers == 0)
                {
                    _writer.Close();
                    _writer = null;
                }
            }
        }
    }
}

Теоретически предполагается, что это позволит создать потокобезопасный одноэлементный экземпляр -для индекса (, названного здесь «индекс -тест» ), где у меня есть два общедоступных метода, Search()и Write(), которые могут вызываться из веб-приложения ASP.NET, не беспокоясь о безопасности потоков? (Если это неверно, сообщите мне ).

Была одна вещь, которая меня сейчас немного беспокоит:

Как изящно закрыть эти экземпляры на Application_Endв файле Global.asax.cs, чтобы, если я хочу перезапустить свое веб-приложение в IIS,Я не собираюсь получать кучу отказов write.lock и т. д.?

Все, о чем я могу думать, это:

public void Close()
{
    lock(syncRoot)
    {
        _searcher.Close();
        _searcher.Dispose();
        _searcher = null;

        _writer.Close();
        _writer.Dispose();
        _writer = null;
    }
}

и вызывая это в Application_End, но если у меня есть какие-либо активные искатели или писатели, приведет ли это к повреждению индекса?

Любая помощь или предложения очень ценятся. Благодарю.

10
задан Community 23 May 2017 в 12:34
поделиться