Beispiel #1
0
        public IEnumerable <string> QueryDocumentIds(string index, IndexQuery query, CancellationTokenSource tokenSource, out bool stale)
        {
            var queryStat = AddToCurrentlyRunningQueryList(index, query, tokenSource);

            try
            {
                bool             isStale   = false;
                HashSet <string> loadedIds = null;
                TransactionalStorage.Batch(
                    actions =>
                {
                    var definition = IndexDefinitionStorage.GetIndexDefinition(index);
                    if (definition == null)
                    {
                        throw new ArgumentException("specified index definition was not found", "index");
                    }

                    isStale = actions.Staleness.IsIndexStale(definition.IndexId, query.Cutoff, null);

                    if (isStale == false && query.Cutoff == null)
                    {
                        var indexInstance = Database.IndexStorage.GetIndexInstance(index);
                        isStale           = isStale || (indexInstance != null && indexInstance.IsMapIndexingInProgress);
                    }

                    if (isStale && actions.Staleness.IsIndexStaleByTask(definition.IndexId, query.Cutoff) == false &&
                        actions.Staleness.IsReduceStale(definition.IndexId) == false)
                    {
                        var viewGenerator = IndexDefinitionStorage.GetViewGenerator(index);
                        if (viewGenerator == null)
                        {
                            throw new ArgumentException("specified index definition was not found", "index");
                        }

                        var forEntityNames  = viewGenerator.ForEntityNames.ToList();
                        var lastIndexedEtag = actions.Indexing.GetIndexStats(definition.IndexId).LastIndexedEtag;

                        if (Database.LastCollectionEtags.HasEtagGreaterThan(forEntityNames, lastIndexedEtag) == false)
                        {
                            isStale = false;
                        }
                    }

                    var indexFailureInformation = actions.Indexing.GetFailureRate(definition.IndexId);

                    if (indexFailureInformation.IsInvalidIndex)
                    {
                        throw new IndexDisabledException(indexFailureInformation);
                    }
                    loadedIds = new HashSet <string>(from queryResult in Database.IndexStorage.Query(index, query, result => true, new FieldsToFetch(null, false, Constants.DocumentIdFieldName), Database.IndexQueryTriggers, tokenSource.Token)
                                                     select queryResult.Key);
                });
                stale = isStale;
                return(loadedIds);
            }
            finally
            {
                RemoveFromCurrentlyRunningQueryList(index, queryStat);
            }
        }
Beispiel #2
0
        internal void DeleteDocumentFromIndexesForCollection(string key, string collection, IStorageActionsAccessor actions)
        {
            foreach (var indexName in IndexDefinitionStorage.IndexNames)
            {
                AbstractViewGenerator abstractViewGenerator =
                    IndexDefinitionStorage.GetViewGenerator(indexName);
                if (abstractViewGenerator == null)
                {
                    continue;
                }


                if (collection != null &&             // the document has a entity name
                    abstractViewGenerator.ForEntityNames.Count > 0)
                // the index operations on specific entities
                {
                    if (abstractViewGenerator.ForEntityNames.Contains(collection) == false)
                    {
                        continue;
                    }
                }

                var instance = IndexDefinitionStorage.GetIndexDefinition(indexName);
                var task     = actions.GetTask(x => x.Index == instance.IndexId, new RemoveFromIndexTask
                {
                    Index = instance.IndexId
                });
                task.Keys.Add(key);
            }
        }
Beispiel #3
0
        private void TryApplyPrecomputedBatchForNewIndex(Index index, IndexDefinition definition)
        {
            var generator = IndexDefinitionStorage.GetViewGenerator(definition.IndexId);

            if (generator.ForEntityNames.Count == 0)
            {
                // we don't optimize if we don't have what to optimize _on, we know this is going to return all docs.
                // no need to try to optimize that, then
                index.IsMapIndexingInProgress = false;
                return;
            }

            try
            {
                Task.Factory.StartNew(() => ApplyPrecomputedBatchForNewIndex(index, generator),
                                      TaskCreationOptions.LongRunning)
                .ContinueWith(t =>
                {
                    if (t.IsFaulted)
                    {
                        Log.Warn("Could not apply precomputed batch for index " + index, t.Exception);
                    }
                    index.IsMapIndexingInProgress = false;
                    WorkContext.ShouldNotifyAboutWork(() => "Precomputed indexing batch for " + index.PublicName + " is completed");
                    WorkContext.NotifyAboutWork();
                });
            }
            catch (Exception)
            {
                index.IsMapIndexingInProgress = false;
                throw;
            }
        }
Beispiel #4
0
        public string[] GetIndexFields(string index)
        {
            var abstractViewGenerator = IndexDefinitionStorage.GetViewGenerator(index);

            if (abstractViewGenerator == null)
            {
                return(new string[0]);
            }
            return(abstractViewGenerator.Fields);
        }
Beispiel #5
0
        private Index CreateIndexImplementation(string directoryPath, IndexDefinition indexDefinition, Lucene.Net.Store.Directory directory)
        {
            var viewGenerator       = indexDefinitionStorage.GetViewGenerator(indexDefinition.Name);
            var indexImplementation = indexDefinition.IsMapReduce
                                                                                ? (Index) new MapReduceIndex(directory, directoryPath, indexDefinition, viewGenerator, documentDatabase.WorkContext)
                                                                                : new SimpleIndex(directory, directoryPath, indexDefinition, viewGenerator, documentDatabase.WorkContext);

            configuration.Container.SatisfyImportsOnce(indexImplementation);

            return(indexImplementation);
        }
Beispiel #6
0
        private void TryApplyPrecomputedBatchForNewIndex(Index index, IndexDefinition definition)
        {
            var generator = IndexDefinitionStorage.GetViewGenerator(definition.IndexId);

            if (generator.ForEntityNames.Count == 0 && index.IsTestIndex == false)
            {
                // we don't optimize if we don't have what to optimize _on_, we know this is going to return all docs.
                // no need to try to optimize that, then
                index.IsMapIndexingInProgress = false;
                return;
            }

            try
            {
                var cts = new CancellationTokenSource();

                var task = Task
                           .Factory
                           .StartNew(() => ApplyPrecomputedBatchForNewIndex(index, generator, index.IsTestIndex == false ? Database.Configuration.MaxNumberOfItemsToProcessInSingleBatch : Database.Configuration.Indexing.MaxNumberOfItemsToProcessInTestIndexes, cts), TaskCreationOptions.LongRunning)
                           .ContinueWith(t =>
                {
                    if (t.IsFaulted)
                    {
                        Log.Warn("Could not apply precomputed batch for index " + index, t.Exception);
                    }
                    index.IsMapIndexingInProgress = false;
                    WorkContext.ShouldNotifyAboutWork(() => "Precomputed indexing batch for " + index.PublicName + " is completed");
                    WorkContext.NotifyAboutWork();
                });

                long id;
                Database
                .Tasks
                .AddTask(
                    task,
                    new TaskBasedOperationState(task),
                    new TaskActions.PendingTaskDescription
                {
                    StartTime = DateTime.UtcNow,
                    Payload   = index.PublicName,
                    TaskType  = TaskActions.PendingTaskType.NewIndexPrecomputedBatch
                },
                    out id,
                    cts);
            }
            catch (Exception)
            {
                index.IsMapIndexingInProgress = false;
                throw;
            }
        }
Beispiel #7
0
 private void AddIndexingTask(IStorageActionsAccessor actions, JToken metadata, Func <Task> taskGenerator)
 {
     foreach (var indexName in IndexDefinitionStorage.IndexNames)
     {
         var viewGenerator = IndexDefinitionStorage.GetViewGenerator(indexName);
         if (viewGenerator == null)
         {
             continue;
         }
         var entityName = metadata.Value <string>("Raven-Entity-Name");
         if (viewGenerator.ForEntityName != null &&
             viewGenerator.ForEntityName != entityName)
         {
             continue;
         }
         var task = taskGenerator();
         task.Index = indexName;
         actions.Tasks.AddTask(task, DateTime.UtcNow);
     }
 }
Beispiel #8
0
        public QueryResult Query(string index, IndexQuery query)
        {
            index = IndexDefinitionStorage.FixupIndexName(index);
            var list  = new List <JObject>();
            var stale = false;
            Tuple <DateTime, Guid> indexTimestamp = null;

            TransactionalStorage.Batch(
                actions =>
            {
                string entityName = null;


                var viewGenerator = IndexDefinitionStorage.GetViewGenerator(index);
                if (viewGenerator == null)
                {
                    throw new InvalidOperationException("Could not find index named: " + index);
                }

                entityName = viewGenerator.ForEntityName;

                stale          = actions.Staleness.IsIndexStale(index, query.Cutoff, entityName);
                indexTimestamp = actions.Staleness.IndexLastUpdatedAt(index);
                var indexFailureInformation = actions.Indexing.GetFailureRate(index);
                if (indexFailureInformation.IsInvalidIndex)
                {
                    throw new IndexDisabledException(indexFailureInformation);
                }
                var docRetriever    = new DocumentRetriever(actions, ReadTriggers);
                var indexDefinition = GetIndexDefinition(index);
                var fieldsToFetch   = new FieldsToFetch(query.FieldsToFetch, query.AggregationOperation,
                                                        viewGenerator.ReduceDefinition == null
                                                                                ? Abstractions.Data.Constants.DocumentIdFieldName
                                                                                : Abstractions.Data.Constants.ReduceKeyFieldName);
                var collection = from queryResult in IndexStorage.Query(index, query, result => docRetriever.ShouldIncludeResultInQuery(result, indexDefinition, fieldsToFetch), fieldsToFetch)
                                 select docRetriever.RetrieveDocumentForQuery(queryResult, indexDefinition, fieldsToFetch)
                                 into doc
                                 where doc != null
                                 select doc;

                var transformerErrors = new List <string>();
                IEnumerable <JObject> results;
                if (viewGenerator != null &&
                    query.SkipTransformResults == false &&
                    viewGenerator.TransformResultsDefinition != null)
                {
                    var robustEnumerator = new RobustEnumerator
                    {
                        OnError =
                            (exception, o) =>
                            transformerErrors.Add(string.Format("Doc '{0}', Error: {1}", Index.TryGetDocKey(o),
                                                                exception.Message))
                    };
                    var dynamicJsonObjects = collection.Select(x => new DynamicJsonObject(x.ToJson())).ToArray();
                    results =
                        robustEnumerator.RobustEnumeration(
                            dynamicJsonObjects,
                            source => viewGenerator.TransformResultsDefinition(docRetriever, source))
                        .Select(JsonExtensions.ToJObject);
                }
                else
                {
                    results = collection.Select(x => x.ToJson());
                }

                list.AddRange(results);

                if (transformerErrors.Count > 0)
                {
                    throw new InvalidOperationException("The transform results function failed.\r\n" + string.Join("\r\n", transformerErrors));
                }
            });
            return(new QueryResult
            {
                IndexName = index,
                Results = list,
                IsStale = stale,
                SkippedResults = query.SkippedResults.Value,
                TotalResults = query.TotalSize.Value,
                IndexTimestamp = indexTimestamp.Item1,
                IndexEtag = indexTimestamp.Item2
            });
        }
Beispiel #9
0
        private Action TryCreateTaskForApplyingPrecomputedBatchForNewIndex(Index index, IndexDefinition definition)
        {
            if (Database.Configuration.MaxPrecomputedBatchSizeForNewIndex <= 0) //precaution -> should never be lower than 0
            {
                index.IsMapIndexingInProgress = false;
                return(null);
            }

            var generator = IndexDefinitionStorage.GetViewGenerator(definition.IndexId);

            if (generator.ForEntityNames.Count == 0 && index.IsTestIndex == false)
            {
                // we don't optimize if we don't have what to optimize _on_, we know this is going to return all docs.
                // no need to try to optimize that, then
                index.IsMapIndexingInProgress = false;
                return(null);
            }

            //only one precomputed batch can run at a time except for test indexes
            if (index.IsTestIndex == false)
            {
                lock (precomputedLock)
                {
                    if (isPrecomputedBatchForNewIndexIsRunning)
                    {
                        index.IsMapIndexingInProgress = false;
                        return(null);
                    }

                    isPrecomputedBatchForNewIndexIsRunning = true;
                }
            }

            try
            {
                var cts  = new CancellationTokenSource();
                var task = new Task(() =>
                {
                    try
                    {
                        ApplyPrecomputedBatchForNewIndex(index, generator,
                                                         index.IsTestIndex == false ?
                                                         Database.Configuration.MaxPrecomputedBatchSizeForNewIndex :
                                                         Database.Configuration.Indexing.MaxNumberOfItemsToProcessInTestIndexes, cts);
                    }
                    catch (TotalDataSizeExceededException e)
                    {
                        //expected error
                        Log.Info(e.Message);
                    }
                    catch (Exception e)
                    {
                        Log.Warn("Could not apply precomputed batch for index " + index, e);
                    }
                    finally
                    {
                        if (index.IsTestIndex == false)
                        {
                            isPrecomputedBatchForNewIndexIsRunning = false;
                        }
                        index.IsMapIndexingInProgress = false;
                        WorkContext.ShouldNotifyAboutWork(() => "Precomputed indexing batch for " + index.PublicName + " is completed");
                        WorkContext.NotifyAboutWork();
                    }
                }, TaskCreationOptions.LongRunning);

                return(() =>
                {
                    try
                    {
                        task.Start();

                        long id;
                        Database
                        .Tasks
                        .AddTask(
                            task,
                            new TaskBasedOperationState(task),
                            new TaskActions.PendingTaskDescription
                        {
                            StartTime = DateTime.UtcNow,
                            Description = index.PublicName,
                            TaskType = TaskActions.PendingTaskType.NewIndexPrecomputedBatch
                        },
                            out id,
                            cts);
                    }
                    catch (Exception)
                    {
                        index.IsMapIndexingInProgress = false;
                        if (index.IsTestIndex == false)
                        {
                            isPrecomputedBatchForNewIndexIsRunning = false;
                        }
                        throw;
                    }
                });
            }
            catch (Exception)
            {
                index.IsMapIndexingInProgress = false;
                if (index.IsTestIndex == false)
                {
                    isPrecomputedBatchForNewIndexIsRunning = false;
                }
                throw;
            }
        }
Beispiel #10
0
        public bool Delete(string key, Etag etag, TransactionInformation transactionInformation, out RavenJObject metadata)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }
            key = key.Trim();

            var deleted = false;

            Log.Debug("Delete a document with key: {0} and etag {1}", key, etag);
            RavenJObject metadataVar = null;

            using (Database.DocumentLock.Lock())
            {
                TransactionalStorage.Batch(actions =>
                {
                    AssertDeleteOperationNotVetoed(key, transactionInformation);
                    if (transactionInformation == null)
                    {
                        Database.DeleteTriggers.Apply(trigger => trigger.OnDelete(key, null));

                        Etag deletedETag;
                        if (actions.Documents.DeleteDocument(key, etag, out metadataVar, out deletedETag))
                        {
                            deleted = true;
                            actions.Indexing.RemoveAllDocumentReferencesFrom(key);
                            WorkContext.MarkDeleted(key);

                            Database.Indexes.CheckReferenceBecauseOfDocumentUpdate(key, actions);

                            foreach (var indexName in IndexDefinitionStorage.IndexNames)
                            {
                                AbstractViewGenerator abstractViewGenerator =
                                    IndexDefinitionStorage.GetViewGenerator(indexName);
                                if (abstractViewGenerator == null)
                                {
                                    continue;
                                }

                                var token = metadataVar.Value <string>(Constants.RavenEntityName);

                                if (token != null && // the document has a entity name
                                    abstractViewGenerator.ForEntityNames.Count > 0)
                                // the index operations on specific entities
                                {
                                    if (abstractViewGenerator.ForEntityNames.Contains(token) == false)
                                    {
                                        continue;
                                    }
                                }

                                var instance = IndexDefinitionStorage.GetIndexDefinition(indexName);
                                var task     = actions.GetTask(x => x.Index == instance.IndexId, new RemoveFromIndexTask
                                {
                                    Index = instance.IndexId
                                });
                                task.Keys.Add(key);
                            }
                            if (deletedETag != null)
                            {
                                Database.Prefetcher.AfterDelete(key, deletedETag);
                            }
                            Database.DeleteTriggers.Apply(trigger => trigger.AfterDelete(key, null));
                        }

                        TransactionalStorage
                        .ExecuteImmediatelyOrRegisterForSynchronization(() =>
                        {
                            Database.DeleteTriggers.Apply(trigger => trigger.AfterCommit(key));
                            Database.Notifications.RaiseNotifications(new DocumentChangeNotification
                            {
                                Id             = key,
                                Type           = DocumentChangeTypes.Delete,
                                TypeName       = (metadataVar != null) ? metadataVar.Value <string>(Constants.RavenClrType) : null,
                                CollectionName = (metadataVar != null) ? metadataVar.Value <string>(Constants.RavenEntityName) : null
                            }, metadataVar);
                        });
                    }
                    else
                    {
                        var doc = actions.Documents.DocumentMetadataByKey(key, null);

                        Database.InFlightTransactionalState.DeleteDocumentInTransaction(transactionInformation, key,
                                                                                        etag,
                                                                                        doc == null ? Etag.Empty : doc.Etag,
                                                                                        UuidGenerator);
                        deleted = doc != null;
                    }

                    WorkContext.ShouldNotifyAboutWork(() => "DEL " + key);
                });

                metadata = metadataVar;
                return(deleted);
            }
        }