From 69ae228549978f0008ae604963122e2b8f33f8ed Mon Sep 17 00:00:00 2001 From: mbdavid Date: Wed, 15 Feb 2017 07:57:37 -0200 Subject: [PATCH] Avoid Storage use Transaction and OpenWrite delete in chunks #484 --- LiteDB/Engine/Engine/Transaction.cs | 5 +++++ LiteDB/Storage/LiteFileStream.cs | 13 +++++++++++-- LiteDB/Storage/LiteStorage.cs | 3 ++- LiteDB/Utils/LiteException.cs | 6 ++++++ 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/LiteDB/Engine/Engine/Transaction.cs b/LiteDB/Engine/Engine/Transaction.cs index 51e9abc6f..a15361d4c 100644 --- a/LiteDB/Engine/Engine/Transaction.cs +++ b/LiteDB/Engine/Engine/Transaction.cs @@ -9,6 +9,11 @@ public partial class LiteEngine : IDisposable { private Stack _transactions = new Stack(); + /// + /// Get transaction stack count. If returns 0, there is no transaction. + /// + internal int TransactionCount { get { return _transactions.Count; } } + /// /// Starts a new transaction keeping all changed from now in memory only until Commit() be executed. /// Lock thread in write mode to not accept other transaction diff --git a/LiteDB/Storage/LiteFileStream.cs b/LiteDB/Storage/LiteFileStream.cs index c54154f03..b3a130651 100644 --- a/LiteDB/Storage/LiteFileStream.cs +++ b/LiteDB/Storage/LiteFileStream.cs @@ -27,7 +27,9 @@ internal LiteFileStream(LiteEngine engine, LiteFileInfo file, FileAccess mode) _file = file; _mode = mode; - if(mode == FileAccess.Read) + if (_engine.TransactionCount > 0) throw LiteException.TransactionNotSupported("LiteFileStream"); + + if (mode == FileAccess.Read) { // initialize first data block _currentChunkData = this.GetChunkData(_currentChunkIndex); @@ -39,7 +41,14 @@ internal LiteFileStream(LiteEngine engine, LiteFileInfo file, FileAccess mode) // delete chunks content if needed if (file.Length > 0) { - _engine.Delete(LiteStorage.CHUNKS, Query.StartsWith("_id", _file.Id + "\\")); + var index = 0; + var deleted = true; + + // delete one-by-one to avoid all pages files dirty in memory + while (deleted) + { + deleted = _engine.Delete(LiteStorage.CHUNKS, LiteFileStream.GetChunckId(_file.Id, index++)); // index zero based + } } // clear size counters diff --git a/LiteDB/Storage/LiteStorage.cs b/LiteDB/Storage/LiteStorage.cs index 51fd3cbc2..a6a576685 100644 --- a/LiteDB/Storage/LiteStorage.cs +++ b/LiteDB/Storage/LiteStorage.cs @@ -6,7 +6,7 @@ namespace LiteDB { /// - /// Storage is a special collection to store files/streams. + /// Storage is a special collection to store files/streams. Transactions are not supported in Upload/Download operations. /// public class LiteStorage { @@ -194,6 +194,7 @@ public IEnumerable FindAll() /// public bool Delete(string id) { + if (_engine.TransactionCount > 0) throw LiteException.TransactionNotSupported("LiteStorage.Delete"); if (id.IsNullOrWhiteSpace()) throw new ArgumentNullException("id"); // remove file reference in _files diff --git a/LiteDB/Utils/LiteException.cs b/LiteDB/Utils/LiteException.cs index 054c657e3..30baea819 100644 --- a/LiteDB/Utils/LiteException.cs +++ b/LiteDB/Utils/LiteException.cs @@ -29,6 +29,7 @@ public class LiteException : Exception public const int ALREADY_EXISTS_COLLECTION_NAME = 122; public const int DATABASE_WRONG_PASSWORD = 123; public const int READ_ONLY_DATABASE = 125; + public const int TRANSACTION_NOT_SUPPORTED = 126; public const int INVALID_FORMAT = 200; public const int DOCUMENT_MAX_DEPTH = 201; @@ -156,6 +157,11 @@ internal static LiteException InvalidDbRef(string path) return new LiteException(INVALID_DBREF, "Invalid value for DbRef in path \"{0}\". Value must be document like {{ $ref: \"?\", $id: ? }}", path); } + internal static LiteException TransactionNotSupported(string method) + { + return new LiteException(TRANSACTION_NOT_SUPPORTED, "Transactions are not supported here: " + method); + } + #endregion #region Document/Mapper Errors