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)); } }
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(); } }
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); }