简体   繁体   English

在ASP.NET MVC站点中使用Lucene.Net进行目录锁定错误

[英]Directory lock error with Lucene.Net usage in an ASP.NET MVC site

I'm building an ASP.NET MVC site where I want to use Lucene.Net for search. 我正在构建一个ASP.NET MVC站点,我想使用Lucene.Net进行搜索。 I've already built a SearchController and all of its methods, but I'm getting an error at runtime that occurs when the SearchController is first initialized. 我已经构建了一个SearchController及其所有方法,但是我在运行时遇到一个错误,这个错误是在首次初始化SearchController时发生的。

In SearchController, here's how I'm creating an IndexWriter: 在SearchController中,这是我如何创建IndexWriter:

public static string IndexLocation = HostingEnvironment.MapPath("~/lucene");
public static Lucene.Net.Analysis.Standard.StandardAnalyzer analyzer = new Lucene.Net.Analysis.Standard.StandardAnalyzer();
public static IndexWriter writer = new IndexWriter(IndexLocation,analyzer);

The error occurs on the last line. 错误发生在最后一行。 Here's the message that I'm getting: 这是我得到的信息:

Lucene.Net.Store.LockObtainFailedException: Lock obtain timed out : SimpleFSLock@C:\\Users\\Username\\Desktop\\SiteSolution\\Site\\lucene\\write.lock Lucene.Net.Store.LockObtainFailedException: Lock获取超时 :SimpleFSLock @ C:\\ Users \\ Username \\ Desktop \\ SiteSolution \\ Site \\ lucene \\ write.lock

Furthermore, here's the stack trace: 此外,这是堆栈跟踪:

[LockObtainFailedException: Lock obtain timed out: SimpleFSLock@C:\Users\Username\Desktop\SiteSolution\Site\lucene\write.lock]
   Lucene.Net.Store.Lock.Obtain(Int64 lockWaitTimeout) in C:\Users\Username\Desktop\Lucene.Net_2_9_2\src\Lucene.Net\Store\Lock.cs:107
   Lucene.Net.Index.IndexWriter.Init(Directory d, Analyzer a, Boolean create, Boolean closeDir, IndexDeletionPolicy deletionPolicy, Boolean autoCommit, Int32 maxFieldLength, IndexingChain indexingChain, IndexCommit commit) in C:\Users\Username\Desktop\Lucene.Net_2_9_2\src\Lucene.Net\Index\IndexWriter.cs:1827
   Lucene.Net.Index.IndexWriter.Init(Directory d, Analyzer a, Boolean closeDir, IndexDeletionPolicy deletionPolicy, Boolean autoCommit, Int32 maxFieldLength, IndexingChain indexingChain, IndexCommit commit) in C:\Users\Username\Desktop\Lucene.Net_2_9_2\src\Lucene.Net\Index\IndexWriter.cs:1801
   Lucene.Net.Index.IndexWriter..ctor(String path, Analyzer a) in C:\Users\Username\Desktop\Lucene.Net_2_9_2\src\Lucene.Net\Index\IndexWriter.cs:1350
   Site.Controllers.SearchController..cctor() in C:\Users\Username\Desktop\SiteSolution\Site\Controllers\SearchController.cs:95

[TypeInitializationException: The type initializer for 'Site.Controllers.SearchController' threw an exception.]

[TargetInvocationException: Exception has been thrown by the target of an invocation.]
   System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandle& ctor, Boolean& bNeedSecurityCheck) +0
   System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean fillCache) +86
   System.RuntimeType.CreateInstanceImpl(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean fillCache) +230
   System.Activator.CreateInstance(Type type, Boolean nonPublic) +67
   System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +80

[InvalidOperationException: An error occurred when trying to create a controller of type 'Site.Controllers.SearchController'. Make sure that the controller has a parameterless public constructor.]
   System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +190
   System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +68
   System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +118
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +46
   System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +63
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +13
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8682818
   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

How can I resolve this issue? 我该如何解决这个问题?

UPDATE: I've started working on this particular project again, and it seems that I haven't fully resolved this issue yet. 更新:我已经开始再次研究这个特定的项目了,似乎我还没有完全解决这个问题。

The real issue is that the write.lock file isn't being removed after index usage ends . 真正的问题是在索引使用结束后没有删除write.lock文件 Based on the answer I have accepted, I understand the basic implementation logic, but I'm not sure if I have implemented it correctly. 基于我接受的答案,我理解基本的实现逻辑,但我不确定我是否已正确实现它。 Here are some other methods in my class that are probably invalid: 以下是我班级中可能无效的其他一些方法:

    public ActionResult Search(string query)
    {

        var reader = writer.GetReader(); // Get reader from writer
        var searcher = new IndexSearcher(reader); // Build IndexSearch

        //Execute search...

        // Dispose of objects
        searcher = null;
        reader = null;

        return View();
    }

    public void AddToIndex(Document doc)
    {
        writer.AddDocument(doc);
        writer.Flush();
        writer.Optimize();
        writer.Flush();
    }

    private bool disposed = false;

    protected override void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Release managed resources.
            }
            try
            {
                writer.Close();
                writer = null;
            }
            catch
            {

            }
            // Release unmanaged resources.
            // Set large fields to null.
            // Call Dispose on your base class.
            disposed = true;
        }
        base.Dispose(disposing);
    }

Any thoughts? 有什么想法吗?

The reason why this happens is that the writer creates an empty file called write.lock as a cross-process lock. 发生这种情况的原因是编写器创建了一个名为write.lock的空文件作为跨进程锁。 When that file exists, Lucene assumes that someone has a write lock on that directory. 当该文件存在时,Lucene假定有人在该目录上有写锁定。

When you terminate your process incorrectly, the file will not get deleted. 如果错误地终止进程,则不会删除该文件。 So Lucene thinks that someone is still holding on to the lock. 所以Lucene认为有人仍然坚持锁定。 That's why you should always have a finally statement which closes the index. 这就是为什么你应该总是有一个关闭索引的finally语句。

If you are sure that the file is there in error (ie no Lucene processes are running) it is fine to just delete the file. 如果你确定该文件存在错误(即没有运行Lucene进程),只需删除该文件即可。 Your index may, however, be in a corrupted state, since the writing was obviously terminated midstream. 但是,您的索引可能处于损坏状态,因为写作显然是在中途终止。

Seems to be a dead-lock on lucene. 似乎是对lucene的死锁。

If supposedly NO index update into the collection, 如果假设没有索引更新到集合中,
simply remove this lock file C:\\Users\\Username\\Desktop\\SiteSolution\\Site\\lucene\\write.lock . 只需删除此锁定文件C:\\Users\\Username\\Desktop\\SiteSolution\\Site\\lucene\\write.lock

After that re-run the index writing. 之后重新运行索引编写。

try
{
    writer = new IndexWriter(directory, new StandardAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED);
}

catch (LockObtainFailedException ex)
{
     DirectoryInfo indexDirInfo = new DirectoryInfo(directory);
     FSDirectory indexFSDir = FSDirectory.Open(indexDirInfo, new Lucene.Net.Store.SimpleFSLockFactory(indexDirInfo));
     IndexWriter.Unlock(indexFSDir);
     writer = new IndexWriter(directory, new StandardAnalyzer(), IndexWriter.MaxFieldLength.UNLIMITED);
}

Researching this myself it seems that the indended approach would be to use multiple physical indexes and then merge them using the IndexWriter's .addIndexesNoOptimize or .addIndexes to merge all concurrent index changes. 自己研究这个似乎是indended方法是使用多个物理索引,然后使用IndexWriter的.addIndexesNoOptimize或.addIndexes合并它们以合并所有并发索引更改。

Lucene documentation Lucene文档

没有自己检查但是不会这样(在创建azureDirectory对象后写)?

azureDirectory.ClearLock("write.lock")

I encountered the same issue and I was using an IProviderContext. 我遇到了同样的问题,我正在使用IProviderContext。 In my case I had to: Optimize,Commit and Dispose the ProviderContext. 在我的情况下,我不得不:优化,提交和处置ProviderContext。

providerContext.Optimize();
providerContext.Commit();
providerContext.Dispose();

I hope this helps. 我希望这有帮助。 After implementing the above snippet, my index rebuilt successfully. 实现上面的代码片段后,我的索引成功重建。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM