mbdavid / LiteDB

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

[BUG] InsertBulk causes LiteDB.LiteException #2426

Closed JKamsker closed 4 months ago

JKamsker commented 4 months ago

Version Which LiteDB version/OS/.NET framework version are you using. (REQUIRED) LiteDB: 5.0.18 Windows 10 .NET 6 and 8 (Happens in both)

Describe the bug Here I insert multiple entities using InsertBulk in a loop.

Code to Reproduce Sometimes happens pretty frequently, but usually it requires some program restarts to make it happen. Here download the repo and hit f5.

or

using LiteDB;

namespace LiteDbMigrationSampleTester.Repro;

internal class Class1
{
    public static void Test()
    {
        while (true)
        {
            if (File.Exists("lite.db"))
            {
                File.Delete("lite.db");
            }
            using (var db = new LiteDatabase("lite.db"))
            {
                SeedData(db.GetCollection<ModelA>("modelA"), 500);
            }

            using (var db = new LiteDatabase("lite.db"))
            {
                _ = db.GetCollection<ModelA>("modelA").Query().Limit(10).ToList();
            }

            Console.WriteLine("Seeded");
        }
    }

    private static void SeedData(ILiteCollection<ModelA> collection, int count = 1)
    {
        for (var i = 0; i < count; i++)
        {
            var data = SeeedModelA();
            collection.InsertBulk(data);
        }
    }

    private static IEnumerable<ModelA> SeeedModelA()
    {
        return new[]
        {
            new ModelA
            {
                Name = "John",
                Age = 30,
                City = "New York",
                Region = "New York",
                Country = "USA",
                PostalCode = "10001"
            },
            new ModelA
            {
                Name = "Jane",
                Age = 25,
                City = "Los Angeles",
                Region = "California",
                Country = "USA",
                PostalCode = "90001"
            },
            new ModelA
            {
                Name = "Doe",
                Age = 35,
                City = "San Francisco",
                Region = "California",
                Country = "USA",
                PostalCode = "94016"
            },
            new ModelA
            {
                Name = "Doe",
                Age = 35,
                City = "San Francisco",
                Region = "California",
                Country = "USA",
                PostalCode = "94016"
            }
        };
    }

    public class ModelA
    {
        [BsonId]
        public Guid Id { get; set; }

        public string Name { get; set; }
        public int Age { get; set; }

        public string City { get; set; }

        public string Region { get; set; }

        public string Country { get; set; }
        public string PostalCode { get; set; }
    }
}

Expected behavior No exception.

Screenshots/Stacktrace If applicable, add screenshots/stacktrace base.PageType is Empty but should Collection

LiteDB.LiteException
  HResult=0x80131500
  Message=page type must be collection page
  Source=LiteDB
  StackTrace:
   at LiteDB.Constants.ENSURE(Boolean conditional, String message) in LiteDB\Constants.cs:line 62
   at LiteDB.Engine.CollectionPage..ctor(PageBuffer buffer) in LiteDB.Engine\CollectionPage.cs:line 32
   at LiteDB.Engine.BasePage.ReadPage[T](PageBuffer buffer) in LiteDB.Engine\BasePage.cs:line 462
   at LiteDB.Engine.Snapshot.ReadPage[T](UInt32 pageID, FileOrigin& origin, Int64& position, Int32& walVersion) in LiteDB.Engine\Snapshot.cs:line 158
   at LiteDB.Engine.Snapshot.GetPage[T](UInt32 pageID, FileOrigin& origin, Int64& position, Int32& walVersion) in LiteDB.Engine\Snapshot.cs:line 130
   at LiteDB.Engine.Snapshot.GetPage[T](UInt32 pageID) in LiteDB.Engine\Snapshot.cs:line 110
   at LiteDB.Engine.CollectionService.Get(String name, Boolean addIfNotExists, CollectionPage& collectionPage) in LiteDB.Engine\CollectionService.cs:line 41
   at LiteDB.Engine.Snapshot..ctor(LockMode mode, String collectionName, HeaderPage header, UInt32 transactionID, TransactionPages transPages, LockService locker, WalIndexService walIndex, DiskReader reader, Boolean addIfNotExists) in LiteDB.Engine\Snapshot.cs:line 56
   at LiteDB.Engine.TransactionService.<CreateSnapshot>g__create|43_0(<>c__DisplayClass43_0& ) in LiteDB.Engine\TransactionService.cs:line 97
   at LiteDB.Engine.TransactionService.CreateSnapshot(LockMode mode, String collection, Boolean addIfNotExists) in LiteDB.Engine\TransactionService.cs:line 82
   at LiteDB.Engine.LiteEngine.<>c__DisplayClass7_0.<Insert>b__0(TransactionService transaction) in LiteDB.Engine\LiteEngine.cs:line 309
   at LiteDB.Engine.LiteEngine.AutoTransaction[T](Func`2 fn) in LiteDB.Engine\LiteEngine.cs:line 595
   at LiteDB.Engine.LiteEngine.Insert(String collection, IEnumerable`1 docs, BsonAutoId autoId) in LiteDB.Engine\LiteEngine.cs:line 307
   at LiteDB.LiteCollection`1.InsertBulk(IEnumerable`1 entities, Int32 batchSize) in LiteDB\LiteCollection.cs:line 422
   at LiteDB.Migration.ConsoleTest.Seeder.SeedData(ILiteCollection`1 collection, Int32 count) in C:\Users\JK\source\repos\JKamsker\LiteDb.Migration\LiteDB.Migration.Console\Seeder.cs:line 132
   at LiteDB.Migration.ConsoleTest.Program.CreateDbStream(Func`1 dbOpener) in C:\Users\JK\source\repos\JKamsker\LiteDb.Migration\LiteDB.Migration.Console\Program.cs:line 60
   at LiteDB.Migration.ConsoleTest.Program.<Main>d__0.MoveNext() in C:\Users\JK\source\repos\JKamsker\LiteDb.Migration\LiteDB.Migration.Console\Program.cs:line 43
   at LiteDB.Migration.ConsoleTest.Program.<Main>(String[] args)
JKamsker commented 4 months ago

Oh, just noticed, it doesnt delete the log db.... could that be it? If so, i think the logdb should be deleted by litedb in that case before using it...

mbdavid commented 4 months ago

You can call Checkpoint before dispose your LiteDatabase instance. This command will copy the data from the log file to its respective position in the data file (.db).