Ejemplo n.º 1
0
        public override Task <DocumentQueryResult> ExecuteQuery(IndexQueryServerSide query, QueryOperationContext queryContext, long?existingResultEtag, OperationCancelToken token)
        {
            var result = new DocumentQueryResult();

            if (queryContext.AreTransactionsOpened() == false)
            {
                queryContext.OpenReadTransaction();
            }

            FillCountOfResultsAndIndexEtag(result, query.Metadata, queryContext);

            if (query.Metadata.HasOrderByRandom == false && existingResultEtag.HasValue)
            {
                if (result.ResultEtag == existingResultEtag)
                {
                    return(Task.FromResult(DocumentQueryResult.NotModifiedResult));
                }
            }

            var collection = GetCollectionName(query.Metadata.CollectionName, out var indexName);

            using (QueryRunner.MarkQueryAsRunning(indexName, query, token))
            {
                result.IndexName = indexName;

                ExecuteCollectionQuery(result, query, collection, queryContext, pulseReadingTransaction: false, token.Token);

                return(Task.FromResult(result));
            }
        }
Ejemplo n.º 2
0
        public async Task CreateAutoIndexesAndWaitIfNecessary()
        {
            var queryStepsGatherer = new QueryQueryStepGatherer();

            queryStepsGatherer.Visit(RootQueryStep);

            if (_context.AreTransactionsOpened() == false)
            {
                _context.OpenReadTransaction();
            }

            try
            {
                var etag          = DocumentsStorage.ReadLastEtag(_context.Documents.Transaction.InnerTransaction);
                var queryDuration = Stopwatch.StartNew();
                var indexes       = new List <Index>();
                var indexWaiters  = new Dictionary <Index, (IndexQueryServerSide, AsyncWaitForIndexing)>();
                foreach (var queryStepInfo in queryStepsGatherer.QuerySteps)
                {
                    if (string.IsNullOrWhiteSpace(queryStepInfo.QueryStep.Query.From.From.FieldValue) || queryStepInfo.IsIndexQuery)
                    {
                        continue;
                    }
                    var indexQuery = new IndexQueryServerSide(queryStepInfo.QueryStep.GetQueryString, queryStepInfo.QueryStep.QueryParameters);
                    //No sense creating an index for collection queries
                    if (indexQuery.Metadata.IsCollectionQuery)
                    {
                        continue;
                    }
                    var indexCreationInfo = await _dynamicQueryRunner.CreateAutoIndexIfNeeded(indexQuery, true, null, _database.DatabaseShutdown);

                    if (indexCreationInfo.HasCreatedAutoIndex) //wait for non-stale only IF we just created an auto-index
                    {
                        indexes.Add(indexCreationInfo.Index);
                        var queryTimeout = indexQuery.WaitForNonStaleResultsTimeout ?? Index.DefaultWaitForNonStaleResultsTimeout;
                        indexWaiters.Add(indexCreationInfo.Index, (indexQuery, new AsyncWaitForIndexing(queryDuration, queryTimeout, indexCreationInfo.Index)));
                    }
                }

                await WaitForNonStaleResultsInternal(etag, indexes, indexWaiters);
            }
            finally
            {
                //The rest of the code assumes that a Tx is not opened
                _context.CloseTransaction();
            }
        }
Ejemplo n.º 3
0
        private async Task <(List <Match> Matches, GraphQueryPlan QueryPlan, bool NotModified)> GetQueryResults(IndexQueryServerSide query, QueryOperationContext queryContext, long?existingResultEtag, OperationCancelToken token, bool collectIntermediateResults = false)
        {
            var q  = query.Metadata.Query;
            var qp = new GraphQueryPlan(query, queryContext, existingResultEtag, token, Database)
            {
                CollectIntermediateResults = collectIntermediateResults
            };

            qp.BuildQueryPlan();
            qp.OptimizeQueryPlan(); //TODO: audit optimization

            if (query.WaitForNonStaleResults)
            {
                qp.IsStale = await qp.WaitForNonStaleResults();
            }
            else
            {
                await qp.CreateAutoIndexesAndWaitIfNecessary();
            }

            //for the case where we don't wait for non stale results we will override IsStale in the QueryQueryStep steps

            if (queryContext.AreTransactionsOpened() == false)
            {
                queryContext.OpenReadTransaction();
            }

            qp.ResultEtag = DocumentsStorage.ReadLastEtag(queryContext.Documents.Transaction.InnerTransaction);
            if (existingResultEtag.HasValue)
            {
                if (qp.ResultEtag == existingResultEtag)
                {
                    return(null, null, true);
                }
            }
            await qp.Initialize();

            var matchResults = qp.Execute();

            if (query.Metadata.OrderBy != null)
            {
                Sort(matchResults, query.Metadata.OrderBy, Database.Name, query.Query);
            }

            var filter = q.GraphQuery.Where;

            if (filter != null)
            {
                for (int i = 0; i < matchResults.Count; i++)
                {
                    var resultAsJson = new DynamicJsonValue();
                    matchResults[i].PopulateVertices(resultAsJson);

                    using (var result = queryContext.Documents.ReadObject(resultAsJson, "graph/result"))
                    {
                        if (filter.IsMatchedBy(result, query.QueryParameters) == false)
                        {
                            matchResults[i] = default;
                        }
                    }
                }
            }

            if (query.Start > 0)
            {
                matchResults.RemoveRange(0, Math.Min(query.Start, matchResults.Count));
            }

            if (query.PageSize < matchResults.Count)
            {
                matchResults.RemoveRange(query.PageSize, matchResults.Count - query.PageSize);
            }
            return(matchResults, qp, false);
        }