Lucene.NET Lock获取超时错误

时间:2015-12-09 13:14:50

标签: c# azure model-view-controller lucene lucene.net

运行使用某些用户数据(域对象)更新Lucene索引的进程时,我收到以下错误。

  

Lucene.Net.Store.LockObtainFailedException:Lock获取超时:   AzureLock@write.lock。在Lucene.Net.Store.Lock.Obtain(Int64   lockWaitTimeout)in   d:\ Lucene.Net \ FullRepo \ trunk \ src \ core \ Store \ Lock.cs:第97行at   Lucene.Net.Index.IndexWriter.Init(目录d,分析器a,布尔值   create,IndexDeletionPolicy deletionPolicy,Int32 maxFieldLength,   IndexingChain indexingChain,IndexCommit commit)in   d:\ Lucene.Net \ FullRepo \ trunk \ src \ core \ Index \ IndexWriter.cs:第1228行   在Lucene.Net.Index.IndexWriter..ctor(目录d,分析器a,   MaxFieldLength mfl)in   d:\ Lucene.Net \ FullRepo \ trunk \ src \ core \ Index \ IndexWriter.cs:第174行   在   MyApp.ApplicationServices.Search.Users.UsersSearchEngineService.EnsureIndexWriter()   在   MyApp.ApplicationServices.Search.Users.UsersSearchEngineService.DoWriterAction(Action`1   行动)....

我继承了以下代码,而且我对Lucene的了解不是很好,所以任何指针都会受到赞赏。

public class UsersSearchEngineService : IUsersSearchEngineService
{

   private readonly Directory directory;
   private readonly Analyzer analyzer;
   private static IndexWriter indexWriter;
   private static readonly Object WriterLock = new Object();
   private bool disposed;

   public UsersSearchEngineService (ILuceneDirectoryProvider directoryProvider)
    {
        directory = directoryProvider.GetDirectory();
        analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);
    }

    public int UpdateIndex(IEnumerable<User> itemsToIndex)
    {
        var updatedCount = 0;

        foreach (var itemToIndex in itemsToIndex)
        {
            try
            {
                ExecuteRemoveItem(itemToIndex.UserId);

                var document = CreateIndexDocument(itemToIndex);

                DoWriterAction(writer => writer.AddDocument(document));


                updatedCount++;
            }
            catch (Exception ex)
            {
                EventLogProvider.Error("Error updating index for User with id:[{0}]", ex, itemToIndex.UserId);
            }
        }

        DoWriterAction(writer =>
        {
            writer.Commit();
            writer.Optimize();
        });

        return updatedCount;
    }

     private static Document CreateIndexDocument(User itemToIndex)
    {
        var document = new Document();

        document.Add(new Field("id", itemToIndex.UserId.ToString(CultureInfo.InvariantCulture), Field.Store.YES, Field.Index.NOT_ANALYZED));

        //...
        //omitted other fields being added here 
        //...

        return document;
    }

    void ExecuteRemoveItem(int entryId)
    {
        var searchQuery = GetIdSearchQuery(entryId);
        DoWriterAction(writer => writer.DeleteDocuments(searchQuery));

    }

    void DoWriterAction(Action<IndexWriter> action)
        {
            lock (WriterLock)
            {
                EnsureIndexWriter();
            }
            action(indexWriter);
        }


  void EnsureIndexWriter()
    {
        if (indexWriter != null)
        {
            return;
        }

        indexWriter = new IndexWriter(this.directory, this.analyzer, IndexWriter.MaxFieldLength.UNLIMITED);
        indexWriter.SetMergePolicy(new LogDocMergePolicy(indexWriter) { MergeFactor = 5 });

        var retryStrategy = new ExponentialBackoff(5, TimeSpan.FromMilliseconds(200), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(10));

        var retryPolicy = new RetryPolicy<LuceneWriterLockedErrorDetectionStrategy>(retryStrategy);

        retryPolicy.Retrying += (sender, args) => EventLogProvider.Warn("Retrying lock delete Attempt: " + args.CurrentRetryCount);

        if (IndexWriter.IsLocked(this.directory))
        {
            retryPolicy.ExecuteAction(() =>
            {
                EventLogProvider.Info("Something left a lock in the index folder: Attempting to it");
                IndexWriter.Unlock(directory);
                EventLogProvider.Info("Lock Deleted... can proceed");
            });
        }

    }

    ~UsersSearchEngineService ()
    {
        Dispose();
    }

    public void Dispose()
    {
        lock (WriterLock)
        {
            if (!disposed)
            {
                var writer = indexWriter;

                if (writer != null)
                {
                    try
                    {
                        writer.Dispose();
                    }
                    catch (ObjectDisposedException e)
                    {
                        EventLogProvider.Error("Exception while disposing SearchEngineService", e);
                    }
                    indexWriter = null;
                }

                var disposeDirectory = directory;
                if (disposeDirectory != null)
                {
                    try
                    {
                        disposeDirectory.Dispose();
                    }
                    catch (ObjectDisposedException e)
                    {
                        EventLogProvider.Error("Exception while disposing SearchEngineService", e);
                    }
                }

                disposed = true;
            }
        }
        GC.SuppressFinalize(this);
    }

}

如果相关:

  • 应用程序作为Azure Web App托管,运行2个实例

  • 索引存储在Azure存储

  • 该过程作为CMS中定义的计划进程运行。
  • CMS将仅启动允许一个预定进程实例在任何运行 在负载平衡场景中的一次(例如,当运行2时 Azure中的实例)

EnsureIndexWriter方法看起来是否正确?如果没有,应该如何重做?

0 个答案:

没有答案