From ece59bbc1ab91d38ac26dd5e1614f57e6cc538fd Mon Sep 17 00:00:00 2001 From: JKamsker Date: Sat, 1 Jun 2024 19:03:34 +0200 Subject: [PATCH 1/5] Fixed #2471, #2435, #2483 : Releasing read lock when done reading --- LiteDB.Tests/Issues/Issue2471_Test.cs | 49 +++++++++++++++++++ LiteDB/Engine/Query/QueryExecutor.cs | 28 +++++------ .../Utils/Extensions/EnumerableExtensions.cs | 27 ++++++++++ 3 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 LiteDB.Tests/Issues/Issue2471_Test.cs create mode 100644 LiteDB/Utils/Extensions/EnumerableExtensions.cs diff --git a/LiteDB.Tests/Issues/Issue2471_Test.cs b/LiteDB.Tests/Issues/Issue2471_Test.cs new file mode 100644 index 000000000..c6d9ff1a2 --- /dev/null +++ b/LiteDB.Tests/Issues/Issue2471_Test.cs @@ -0,0 +1,49 @@ +using FluentAssertions; + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +using Xunit; + +namespace LiteDB.Tests.Issues; + +public class Issue2471_Test +{ + [Fact] + public void TestFragmentDB_FindByIDException() + { + using var db = new LiteDatabase(":memory:"); + 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().NotThrow(); + } + + [Fact] + public void MultipleReadCleansUpTransaction() + { + using var database = new LiteDatabase(":memory:"); + + var collection = database.GetCollection("test"); + collection.Insert(new BsonDocument { ["_id"] = 1 }); + + for (int i = 0; i < 500; i++) + { + collection.FindById(1); + } + } +} \ No newline at end of file diff --git a/LiteDB/Engine/Query/QueryExecutor.cs b/LiteDB/Engine/Query/QueryExecutor.cs index 10d8e034b..522eb44af 100644 --- a/LiteDB/Engine/Query/QueryExecutor.cs +++ b/LiteDB/Engine/Query/QueryExecutor.cs @@ -1,6 +1,9 @@ -using System; +using LiteDB.Utils.Extensions; + +using System; using System.Collections.Generic; using System.Linq; + using static LiteDB.Constants; namespace LiteDB.Engine @@ -71,8 +74,14 @@ internal BsonDataReader ExecuteQuery(bool executionPlan) transaction.OpenCursors.Add(_cursor); + var enumerable = RunQuery(); + if (isNew) + { + enumerable = enumerable.OnDispose(() => _monitor.ReleaseTransaction(transaction)); + } + // return new BsonDataReader with IEnumerable source - return new BsonDataReader(RunQuery(), _collection, _state); + return new BsonDataReader(enumerable, _collection, _state); IEnumerable RunQuery() { @@ -89,11 +98,6 @@ IEnumerable RunQuery() transaction.OpenCursors.Remove(_cursor); - if (isNew) - { - _monitor.ReleaseTransaction(transaction); - } - yield break; } @@ -111,11 +115,6 @@ IEnumerable RunQuery() transaction.OpenCursors.Remove(_cursor); - if (isNew) - { - _monitor.ReleaseTransaction(transaction); - } - yield break; } @@ -169,11 +168,6 @@ IEnumerable RunQuery() _cursor.Elapsed.Stop(); transaction.OpenCursors.Remove(_cursor); - - if (isNew) - { - _monitor.ReleaseTransaction(transaction); - } }; } diff --git a/LiteDB/Utils/Extensions/EnumerableExtensions.cs b/LiteDB/Utils/Extensions/EnumerableExtensions.cs new file mode 100644 index 000000000..b79c1af12 --- /dev/null +++ b/LiteDB/Utils/Extensions/EnumerableExtensions.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LiteDB.Utils.Extensions +{ + internal static class EnumerableExtensions + { + // calls method on dispose + public static IEnumerable OnDispose(this IEnumerable source, Action onDispose) + { + try + { + foreach (var item in source) + { + yield return item; + } + } + finally + { + onDispose(); + } + } + } +} \ No newline at end of file From 72b1ac28d29100d0fcb380023dba4cff89015cd4 Mon Sep 17 00:00:00 2001 From: JKamsker <11245306+JKamsker@users.noreply.github.com> Date: Tue, 4 Jun 2024 17:48:42 +0200 Subject: [PATCH 2/5] Bump langversion to be able to use newer language features while all TargetFrameworks still build and run --- LiteDB/LiteDB.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/LiteDB/LiteDB.csproj b/LiteDB/LiteDB.csproj index 721395e91..4105be0f3 100644 --- a/LiteDB/LiteDB.csproj +++ b/LiteDB/LiteDB.csproj @@ -28,6 +28,7 @@ true LiteDB.snk true + 8.0