From 45d081bf3c37a54a55b69e49e457a92953ed75e2 Mon Sep 17 00:00:00 2001 From: Takuhiro Hizume Date: Fri, 23 Feb 2024 10:03:45 +0900 Subject: [PATCH] Release transaction with try-finally statement --- LiteDB/Engine/Query/QueryExecutor.cs | 146 +++++++++++++-------------- 1 file changed, 70 insertions(+), 76 deletions(-) diff --git a/LiteDB/Engine/Query/QueryExecutor.cs b/LiteDB/Engine/Query/QueryExecutor.cs index 10d8e034b..99739be68 100644 --- a/LiteDB/Engine/Query/QueryExecutor.cs +++ b/LiteDB/Engine/Query/QueryExecutor.cs @@ -76,103 +76,97 @@ internal BsonDataReader ExecuteQuery(bool executionPlan) IEnumerable RunQuery() { - var snapshot = transaction.CreateSnapshot(_query.ForUpdate ? LockMode.Write : LockMode.Read, _collection, false); - - // no collection, no documents - if (snapshot.CollectionPage == null && _source == null) + try { - // if query use Source (*) need runs with empty data source - if (_query.Select.UseSource) - { - yield return _query.Select.ExecuteScalar(_pragmas.Collation).AsDocument; - } + var snapshot = transaction.CreateSnapshot(_query.ForUpdate ? LockMode.Write : LockMode.Read, _collection, false); - transaction.OpenCursors.Remove(_cursor); - - if (isNew) + // no collection, no documents + if (snapshot.CollectionPage == null && _source == null) { - _monitor.ReleaseTransaction(transaction); + // if query use Source (*) need runs with empty data source + if (_query.Select.UseSource) + { + yield return _query.Select.ExecuteScalar(_pragmas.Collation).AsDocument; + } + yield break; } - yield break; - } - - // execute optimization before run query (will fill missing _query properties instance) - var optimizer = new QueryOptimization(snapshot, _query, _source, _pragmas.Collation); + // execute optimization before run query (will fill missing _query properties instance) + var optimizer = new QueryOptimization(snapshot, _query, _source, _pragmas.Collation); - var queryPlan = optimizer.ProcessQuery(); + var queryPlan = optimizer.ProcessQuery(); - var plan = queryPlan.GetExecutionPlan(); + var plan = queryPlan.GetExecutionPlan(); - // if execution is just to get explan plan, return as single document result - if (executionPlan) - { - yield return queryPlan.GetExecutionPlan(); - - transaction.OpenCursors.Remove(_cursor); - - if (isNew) + // if execution is just to get explan plan, return as single document result + if (executionPlan) { - _monitor.ReleaseTransaction(transaction); + yield return queryPlan.GetExecutionPlan(); + yield break; } - yield break; - } - - // get node list from query - distinct by dataBlock (avoid duplicate) - var nodes = queryPlan.Index.Run(snapshot.CollectionPage, new IndexService(snapshot, _pragmas.Collation, _disk.MAX_ITEMS_COUNT)); + // get node list from query - distinct by dataBlock (avoid duplicate) + var nodes = queryPlan.Index.Run(snapshot.CollectionPage, new IndexService(snapshot, _pragmas.Collation, _disk.MAX_ITEMS_COUNT)); - // get current query pipe: normal or groupby pipe - var pipe = queryPlan.GetPipe(transaction, snapshot, _sortDisk, _pragmas, _disk.MAX_ITEMS_COUNT); + // get current query pipe: normal or groupby pipe + var pipe = queryPlan.GetPipe(transaction, snapshot, _sortDisk, _pragmas, _disk.MAX_ITEMS_COUNT); - // start cursor elapsed timer - _cursor.Elapsed.Start(); - - using (var enumerator = pipe.Pipe(nodes, queryPlan).GetEnumerator()) - { - var read = false; + // start cursor elapsed timer + _cursor.Elapsed.Start(); try { - read = enumerator.MoveNext(); - } - catch (Exception ex) - { - _state.Handle(ex); - throw ex; - } - - while (read) - { - _cursor.Fetched++; - _cursor.Elapsed.Stop(); - - yield return enumerator.Current; - - if (transaction.State != TransactionState.Active) throw new LiteException(0, $"There is no more active transaction for this cursor: {_cursor.Query.ToSQL(_cursor.Collection)}"); - - _cursor.Elapsed.Start(); - - try - { - read = enumerator.MoveNext(); - } - catch (Exception ex) + using (var enumerator = pipe.Pipe(nodes, queryPlan).GetEnumerator()) { - _state.Handle(ex); - throw ex; + var read = false; + + try + { + read = enumerator.MoveNext(); + } + catch (Exception ex) + { + _state.Handle(ex); + throw ex; + } + + while (read) + { + _cursor.Fetched++; + _cursor.Elapsed.Stop(); + + yield return enumerator.Current; + + if (transaction.State != TransactionState.Active) throw new LiteException(0, $"There is no more active transaction for this cursor: {_cursor.Query.ToSQL(_cursor.Collection)}"); + + _cursor.Elapsed.Start(); + + try + { + read = enumerator.MoveNext(); + } + catch (Exception ex) + { + _state.Handle(ex); + throw ex; + } + } } + } + finally + { + // stop cursor elapsed + _cursor.Elapsed.Stop(); } } - - // stop cursor elapsed - _cursor.Elapsed.Stop(); - - transaction.OpenCursors.Remove(_cursor); - - if (isNew) + finally { - _monitor.ReleaseTransaction(transaction); + transaction.OpenCursors.Remove(_cursor); + + if (isNew) + { + _monitor.ReleaseTransaction(transaction); + } } }; }