public (bool MoreWorkFound, Index.CanContinueBatchResult BatchContinuationResult) Execute(QueryOperationContext queryContext, TransactionOperationContext indexContext, Lazy <IndexWriteOperation> writeOperation, IndexingStatsScope stats, CancellationToken token) { var maxTimeForDocumentTransactionToRemainOpen = Debugger.IsAttached == false ? _configuration.MaxTimeForDocumentTransactionToRemainOpen.AsTimeSpan : TimeSpan.FromMinutes(15); var moreWorkFound = false; var batchContinuationResult = Index.CanContinueBatchResult.None; var totalProcessedCount = 0; foreach (var collection in _index.Collections) { using (var collectionStats = stats.For("Collection_" + collection)) { var lastMappedEtag = _indexStorage.ReadLastIndexedEtag(indexContext.Transaction, collection); if (_logger.IsInfoEnabled) { _logger.Info($"Executing map for '{_index.Name}'. Collection: {collection} LastMappedEtag: {lastMappedEtag:#,#;;0}."); } var inMemoryStats = _index.GetStats(collection); var lastEtag = lastMappedEtag; var resultsCount = 0; var pageSize = int.MaxValue; var sw = new Stopwatch(); var keepRunning = true; var lastCollectionEtag = -1L; while (keepRunning) { using (queryContext.OpenReadTransaction()) { sw.Restart(); if (lastCollectionEtag == -1) { lastCollectionEtag = _index.GetLastItemEtagInCollection(queryContext, collection); } var items = GetItemsEnumerator(queryContext, collection, lastEtag, pageSize); using (var itemEnumerator = _index.GetMapEnumerator(items, collection, indexContext, collectionStats, _index.Type)) { while (true) { if (itemEnumerator.MoveNext(queryContext.Documents, out IEnumerable mapResults, out var etag) == false) { if (etag > lastEtag) { lastEtag = etag.Value; } collectionStats.RecordBatchCompletedReason(IndexingWorkType.Map, "No more documents to index"); keepRunning = false; break; } token.ThrowIfCancellationRequested(); var current = itemEnumerator.Current; totalProcessedCount++; collectionStats.RecordMapAttempt(); stats.RecordDocumentSize(current.Size); if (_logger.IsInfoEnabled && totalProcessedCount % 8192 == 0) { _logger.Info($"Executing map for '{_index.Name}'. Processed count: {totalProcessedCount:#,#;;0} etag: {lastEtag:#,#;;0}."); } lastEtag = current.Etag; inMemoryStats.UpdateLastEtag(lastEtag, isTombstone: false); try { current.SkipLuceneDelete = _indexStorage.LowerThanLastDatabaseEtagOnIndexCreation(current.Etag); var numberOfResults = _index.HandleMap(current, mapResults, writeOperation, indexContext, collectionStats); resultsCount += numberOfResults; collectionStats.RecordMapSuccess(); _index.MapsPerSec?.MarkSingleThreaded(numberOfResults); } catch (Exception e) when(e.IsIndexError()) { itemEnumerator.OnError(); _index.ErrorIndexIfCriticalException(e); collectionStats.RecordMapError(); if (_logger.IsInfoEnabled) { _logger.Info($"Failed to execute mapping function on '{current.Id}' for '{_index.Name}'.", e); } collectionStats.AddMapError(current.Id, $"Failed to execute mapping function on {current.Id}. " + $"Exception: {e}"); } var parameters = new CanContinueBatchParameters(collectionStats, IndexingWorkType.Map, queryContext, indexContext, writeOperation, lastEtag, lastCollectionEtag, totalProcessedCount, sw); batchContinuationResult = _index.CanContinueBatch(in parameters, ref maxTimeForDocumentTransactionToRemainOpen); if (batchContinuationResult != Index.CanContinueBatchResult.True) { keepRunning = batchContinuationResult == Index.CanContinueBatchResult.RenewTransaction; break; } if (totalProcessedCount >= pageSize) { keepRunning = false; break; } } } } } if (lastMappedEtag == lastEtag) { // the last mapped etag hasn't changed continue; } moreWorkFound = true; if (_logger.IsInfoEnabled) { _logger.Info($"Executed map for '{_index.Name}' index and '{collection}' collection. Got {resultsCount:#,#;;0} map results in {collectionStats.Duration.TotalMilliseconds:#,#;;0} ms."); } if (_index.Type.IsMap()) { _index.SaveLastState(); _indexStorage.WriteLastIndexedEtag(indexContext.Transaction, collection, lastEtag); } else { _mapReduceContext.ProcessedDocEtags[collection] = lastEtag; } } } return(moreWorkFound, batchContinuationResult); }