Пример #1
0
        // Protected implementation of Dispose pattern.
        protected virtual void Dispose(bool dispose)
        {
            if (_state == TransactionState.Disposed)
            {
                return;
            }

            ENSURE(_state != TransactionState.Disposed, "transaction must be active before call Done");

            // clean snapshots if there is no commit/rollback
            if (_state == TransactionState.Active && _snapshots.Count > 0)
            {
                // release writable snapshots
                foreach (var snapshot in _snapshots.Values.Where(x => x.Mode == LockMode.Write))
                {
                    // discard all dirty pages
                    _disk.DiscardDirtyPages(snapshot.GetWritablePages(true, true).Select(x => x.Buffer));

                    // discard all clean pages
                    _disk.DiscardCleanPages(snapshot.GetWritablePages(false, true).Select(x => x.Buffer));
                }

                // release buffers in read-only snaphosts
                foreach (var snapshot in _snapshots.Values.Where(x => x.Mode == LockMode.Read))
                {
                    foreach (var page in snapshot.LocalPages)
                    {
                        page.Buffer.Release();
                    }

                    snapshot.CollectionPage?.Buffer.Release();
                }
            }

            _reader.Dispose();

            _state = TransactionState.Disposed;

            if (!dispose)
            {
                // Remove transaction monitor's dictionary
                _monitor.ReleaseTransaction(this);
            }
        }
Пример #2
0
        /// <summary>
        /// Run query definition into engine. Execute optimization to get query planner
        /// </summary>
        internal BsonDataReader ExecuteQuery(bool executionPlan)
        {
            // get current transaction (if contains a explicit transaction) or a query-only transaction
            var transaction = _monitor.GetTransaction(true, true, out var isNew);

            transaction.OpenCursors.Add(_cursor);

            // return new BsonDataReader with IEnumerable source
            return(new BsonDataReader(RunQuery(), _collection));

            IEnumerable <BsonDocument> RunQuery()
            {
                var snapshot = transaction.CreateSnapshot(_query.ForUpdate ? LockMode.Write : LockMode.Read, _collection, false);

                // no collection, no documents
                if (snapshot.CollectionPage == null && _source == null)
                {
                    // if query use Source (*) need runs with empty data source
                    if (_query.Select.UseSource)
                    {
                        yield return(_query.Select.ExecuteScalar(_pragmas.Collation).AsDocument);
                    }

                    transaction.OpenCursors.Remove(_cursor);

                    if (isNew)
                    {
                        _monitor.ReleaseTransaction(transaction);
                    }

                    yield break;
                }

                // execute optimization before run query (will fill missing _query properties instance)
                var optimizer = new QueryOptimization(snapshot, _query, _source, _pragmas.Collation);

                var queryPlan = optimizer.ProcessQuery();

                // 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)
                    {
                        _monitor.ReleaseTransaction(transaction);
                    }

                    yield break;
                }

                // get node list from query - distinct by dataBlock (avoid duplicate)
                var nodes = queryPlan.Index.Run(snapshot.CollectionPage, new IndexService(snapshot, _pragmas.Collation));

                // get current query pipe: normal or groupby pipe
                var pipe = queryPlan.GetPipe(transaction, snapshot, _sortDisk, _pragmas);

                try
                {
                    // start cursor elapsed timer
                    _cursor.Elapsed.Start();

                    // call safepoint just before return each document
                    foreach (var doc in pipe.Pipe(nodes, queryPlan))
                    {
                        _cursor.Fetched++;
                        _cursor.Elapsed.Stop();

                        yield return(doc);

                        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();
                    }
                }
                finally
                {
                    // stop cursor elapsed
                    _cursor.Elapsed.Stop();

                    transaction.OpenCursors.Remove(_cursor);

                    if (isNew)
                    {
                        _monitor.ReleaseTransaction(transaction);
                    }
                }
            };
        }