mbdavid / LiteDB

LiteDB - A .NET NoSQL Document Store in a single data file
http://www.litedb.org
MIT License
8.35k stars 1.22k forks source link

[BUG] LockRecursionException thrown in very simple use case #2471

Closed Costigan closed 3 weeks ago

Costigan commented 2 months ago

Version 5.0.19

Describe the bug Here is an MSTest test case that passes, indicating that the Checkpoint() call throws a LockRecursionException with the 'Write lock may not be acquired with read lock held' message that's mentioned in some other bug reports. This is a simplification of an exception that's being thrown in my application that I don't understand. Also, I'm a new LiteDB user and could easily have misunderstood something. Have I forgotten to do something?

This code creates a new database using an expandable MemoryStream, then adds an object to it, receiving the new id. Then, it looks up the document by this new id receiving that document (a copy). Finally, the code tries to checkpoint the changes. At this point, LiteDB throws a LockRecursionException, presumably because it's trying to write changes to the memory stream and a read lock is held by something. This isn't an iterator that hasn't been allowed to finish, so I'm stumped.

Code to Reproduce [TestMethod] public void TestFragmentDB_FindByIDException() { var db = new LiteDatabase(new MemoryStream()); var collection = db.GetCollection("fragtest");

        var fragment = new object { };
        var id = collection.Insert(fragment);

        id.Should().BeGreaterThan(0);

        var frag2 = collection.FindById(id);
        frag2.Should().NotBeNull();

        Action act = () => db.Checkpoint();

        act.Should().Throw<LockRecursionException>();

        db.Dispose();
    }

Expected behavior I expect db.Checkpoint() to not throw an exception.

Screenshots/Stacktrace image image

Additional context This seems like a very basic use case, so it's most likely that I'm doing something wrong.

If I remove the FindById() call, the checkpoint does not throw the exception.

I'm running this code in the TestExplorer in Visual Studio, which I think is MSTest, but that doesn't seem to be the issue. If I copy this code to the Program.cs file of my (desktop) application and run it in the main thread before the GUI is created, the code throws the same exception

I believe the test runner configured to run tests sequentially. Also, I'm running this test alone ... no other tests are running, using LiteDB or otherwise.

myblindy commented 2 months ago

I've also gotten this exception on Checkpoint(), it seems very unstable right now.

My scenario was a regular file-backed db written once with a bunch of files added to the basic FileStore (as streams, written individually). Calling Checkpoint() before closing the db (and of course, all of the streams) crashes with that exception.

JKamsker commented 3 weeks ago

Thanks for the report, i have found and fixed the issue in https://github.com/mbdavid/LiteDB/pull/2488