From b2037bc3cb6bd3b5c8149258194c1aeaafccb1bc Mon Sep 17 00:00:00 2001 From: Joyless <65855333+Joy-less@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:13:21 +0100 Subject: [PATCH 1/3] Fix #2534 --- LiteDB.Tests/Issues/Issue2534_Tests.cs | 25 ++++ LiteDB/Client/Shared/SharedEngine.cs | 187 ++++++------------------- 2 files changed, 69 insertions(+), 143 deletions(-) create mode 100644 LiteDB.Tests/Issues/Issue2534_Tests.cs diff --git a/LiteDB.Tests/Issues/Issue2534_Tests.cs b/LiteDB.Tests/Issues/Issue2534_Tests.cs new file mode 100644 index 000000000..5605eb540 --- /dev/null +++ b/LiteDB.Tests/Issues/Issue2534_Tests.cs @@ -0,0 +1,25 @@ +using Xunit; + +namespace LiteDB.Tests.Issues; + +public class Issue2534_Tests { + [Fact] + public void Test() { + using LiteDatabase database = new(new ConnectionString() + { + Filename = "Demo.db", + Connection = ConnectionType.Shared, + }); + ILiteCollection accounts = database.GetCollection("Accounts"); + if (accounts.Count() < 3) + { + accounts.Insert(new BsonDocument()); + accounts.Insert(new BsonDocument()); + accounts.Insert(new BsonDocument()); + } + foreach (BsonDocument document in accounts.FindAll()) + { + accounts.Update(document); + } + } +} \ No newline at end of file diff --git a/LiteDB/Client/Shared/SharedEngine.cs b/LiteDB/Client/Shared/SharedEngine.cs index 62bb35a65..4555e977c 100644 --- a/LiteDB/Client/Shared/SharedEngine.cs +++ b/LiteDB/Client/Shared/SharedEngine.cs @@ -46,7 +46,8 @@ public SharedEngine(EngineSettings settings) /// /// Open database in safe mode /// - private void OpenDatabase() + /// true if successfully opened; false if already open + private bool OpenDatabase() { try { @@ -61,6 +62,7 @@ private void OpenDatabase() try { _engine = new LiteEngine(_settings); + return true; } catch { @@ -68,6 +70,10 @@ private void OpenDatabase() throw; } } + else + { + return false; + } } /// @@ -142,39 +148,27 @@ public bool Rollback() public IBsonDataReader Query(string collection, Query query) { - this.OpenDatabase(); + bool opened = this.OpenDatabase(); var reader = _engine.Query(collection, query); - return new SharedDataReader(reader, () => this.CloseDatabase()); + return new SharedDataReader(reader, () => + { + if (opened) + { + this.CloseDatabase(); + } + }); } public BsonValue Pragma(string name) { - this.OpenDatabase(); - - try - { - return _engine.Pragma(name); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.Pragma(name)); } public bool Pragma(string name, BsonValue value) { - this.OpenDatabase(); - - try - { - return _engine.Pragma(name, value); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.Pragma(name, value)); } #endregion @@ -183,170 +177,62 @@ public bool Pragma(string name, BsonValue value) public int Checkpoint() { - this.OpenDatabase(); - - try - { - return _engine.Checkpoint(); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.Checkpoint()); } public long Rebuild(RebuildOptions options) { - this.OpenDatabase(); - - try - { - return _engine.Rebuild(options); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.Rebuild(options)); } public int Insert(string collection, IEnumerable docs, BsonAutoId autoId) { - this.OpenDatabase(); - - try - { - return _engine.Insert(collection, docs, autoId); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.Insert(collection, docs, autoId)); } public int Update(string collection, IEnumerable docs) { - this.OpenDatabase(); - - try - { - return _engine.Update(collection, docs); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.Update(collection, docs)); } public int UpdateMany(string collection, BsonExpression extend, BsonExpression predicate) { - this.OpenDatabase(); - - try - { - return _engine.UpdateMany(collection, extend, predicate); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.UpdateMany(collection, extend, predicate)); } public int Upsert(string collection, IEnumerable docs, BsonAutoId autoId) { - this.OpenDatabase(); - - try - { - return _engine.Upsert(collection, docs, autoId); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.Upsert(collection, docs, autoId)); } public int Delete(string collection, IEnumerable ids) { - this.OpenDatabase(); - - try - { - return _engine.Delete(collection, ids); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.Delete(collection, ids)); } public int DeleteMany(string collection, BsonExpression predicate) { - this.OpenDatabase(); - - try - { - return _engine.DeleteMany(collection, predicate); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.DeleteMany(collection, predicate)); } public bool DropCollection(string name) { - this.OpenDatabase(); - - try - { - return _engine.DropCollection(name); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.DropCollection(name)); } public bool RenameCollection(string name, string newName) { - this.OpenDatabase(); - - try - { - return _engine.RenameCollection(name, newName); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.RenameCollection(name, newName)); } public bool DropIndex(string collection, string name) { - this.OpenDatabase(); - - try - { - return _engine.DropIndex(collection, name); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.DropIndex(collection, name)); } public bool EnsureIndex(string collection, string name, BsonExpression expression, bool unique) { - this.OpenDatabase(); - - try - { - return _engine.EnsureIndex(collection, name, expression, unique); - } - finally - { - this.CloseDatabase(); - } + return QueryDatabase(() => _engine.EnsureIndex(collection, name, expression, unique)); } #endregion @@ -374,5 +260,20 @@ protected virtual void Dispose(bool disposing) } } } + + private T QueryDatabase(Func Query) { + bool opened = this.OpenDatabase(); + try + { + return Query(); + } + finally + { + if (opened) + { + this.CloseDatabase(); + } + } + } } } \ No newline at end of file From f18956d040ed4482537572b721dd7477dd006e99 Mon Sep 17 00:00:00 2001 From: Joyless <65855333+Joy-less@users.noreply.github.com> Date: Sat, 5 Oct 2024 19:57:38 +0100 Subject: [PATCH 2/3] Update test packages --- LiteDB.Tests/LiteDB.Tests.csproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/LiteDB.Tests/LiteDB.Tests.csproj b/LiteDB.Tests/LiteDB.Tests.csproj index faed46f9b..a0bd2e807 100644 --- a/LiteDB.Tests/LiteDB.Tests.csproj +++ b/LiteDB.Tests/LiteDB.Tests.csproj @@ -29,15 +29,15 @@ - - - - + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive From 28d560c6a502269408781328e944621d16ac09a3 Mon Sep 17 00:00:00 2001 From: Joyless <65855333+Joy-less@users.noreply.github.com> Date: Sat, 5 Oct 2024 19:58:08 +0100 Subject: [PATCH 3/3] Add recursion tests --- LiteDB.Tests/Engine/Recursion_Tests.cs | 58 ++++++++++++++++++++++++++ LiteDB.Tests/Issues/Issue2534_Tests.cs | 2 +- LiteDB/Client/Shared/SharedEngine.cs | 33 ++++++++------- 3 files changed, 76 insertions(+), 17 deletions(-) create mode 100644 LiteDB.Tests/Engine/Recursion_Tests.cs diff --git a/LiteDB.Tests/Engine/Recursion_Tests.cs b/LiteDB.Tests/Engine/Recursion_Tests.cs new file mode 100644 index 000000000..63968c960 --- /dev/null +++ b/LiteDB.Tests/Engine/Recursion_Tests.cs @@ -0,0 +1,58 @@ +using System; +using Xunit; + +namespace LiteDB.Tests.Engine; + +public class Recursion_Tests { + [Fact] + public void UpdateInFindAll() + { + Test(collection => + { + foreach (BsonDocument document in collection.FindAll()) + { + collection.Update(document); + } + }); + } + [Fact] + public void InsertDeleteInFindAll() + { + Test(collection => + { + foreach (BsonDocument document in collection.FindAll()) + { + BsonValue id = collection.Insert(new BsonDocument()); + collection.Delete(id); + } + }); + } + [Fact] + public void QueryInFindAll() + { + Test(collection => + { + foreach (BsonDocument document in collection.FindAll()) + { + collection.Query().Count(); + } + }); + } + + private void Test(Action> action) + { + using LiteDatabase database = new(new ConnectionString() + { + Filename = "Demo.db", + Connection = ConnectionType.Shared, + }); + ILiteCollection accounts = database.GetCollection("Recursion"); + if (accounts.Count() < 3) + { + accounts.Insert(new BsonDocument()); + accounts.Insert(new BsonDocument()); + accounts.Insert(new BsonDocument()); + } + action(accounts); + } +} \ No newline at end of file diff --git a/LiteDB.Tests/Issues/Issue2534_Tests.cs b/LiteDB.Tests/Issues/Issue2534_Tests.cs index 5605eb540..cce4cda07 100644 --- a/LiteDB.Tests/Issues/Issue2534_Tests.cs +++ b/LiteDB.Tests/Issues/Issue2534_Tests.cs @@ -10,7 +10,7 @@ public void Test() { Filename = "Demo.db", Connection = ConnectionType.Shared, }); - ILiteCollection accounts = database.GetCollection("Accounts"); + ILiteCollection accounts = database.GetCollection("Issue2534"); if (accounts.Count() < 3) { accounts.Insert(new BsonDocument()); diff --git a/LiteDB/Client/Shared/SharedEngine.cs b/LiteDB/Client/Shared/SharedEngine.cs index 4555e977c..c25e7d591 100644 --- a/LiteDB/Client/Shared/SharedEngine.cs +++ b/LiteDB/Client/Shared/SharedEngine.cs @@ -82,7 +82,7 @@ private bool OpenDatabase() private void CloseDatabase() { // Don't dispose the engine while a transaction is running. - if (!this._transactionRunning && _engine != null) + if (!_transactionRunning && _engine != null) { // If no transaction pending, dispose the engine. _engine.Dispose(); @@ -97,17 +97,17 @@ private void CloseDatabase() public bool BeginTrans() { - this.OpenDatabase(); + OpenDatabase(); try { - this._transactionRunning = _engine.BeginTrans(); + _transactionRunning = _engine.BeginTrans(); - return this._transactionRunning; + return _transactionRunning; } catch { - this.CloseDatabase(); + CloseDatabase(); throw; } } @@ -122,8 +122,8 @@ public bool Commit() } finally { - this._transactionRunning = false; - this.CloseDatabase(); + _transactionRunning = false; + CloseDatabase(); } } @@ -137,8 +137,8 @@ public bool Rollback() } finally { - this._transactionRunning = false; - this.CloseDatabase(); + _transactionRunning = false; + CloseDatabase(); } } @@ -148,7 +148,7 @@ public bool Rollback() public IBsonDataReader Query(string collection, Query query) { - bool opened = this.OpenDatabase(); + bool opened = OpenDatabase(); var reader = _engine.Query(collection, query); @@ -156,7 +156,7 @@ public IBsonDataReader Query(string collection, Query query) { if (opened) { - this.CloseDatabase(); + CloseDatabase(); } }); } @@ -239,13 +239,13 @@ public bool EnsureIndex(string collection, string name, BsonExpression expressio public void Dispose() { - this.Dispose(true); + Dispose(true); GC.SuppressFinalize(this); } ~SharedEngine() { - this.Dispose(false); + Dispose(false); } protected virtual void Dispose(bool disposing) @@ -261,8 +261,9 @@ protected virtual void Dispose(bool disposing) } } - private T QueryDatabase(Func Query) { - bool opened = this.OpenDatabase(); + private T QueryDatabase(Func Query) + { + bool opened = OpenDatabase(); try { return Query(); @@ -271,7 +272,7 @@ private T QueryDatabase(Func Query) { { if (opened) { - this.CloseDatabase(); + CloseDatabase(); } } }