コード例 #1
0
        public DocumentDatabase(RavenConfiguration configuration)
        {
            Configuration = configuration;

            configuration.Container.SatisfyImportsOnce(this);

            workContext = new WorkContext {
                IndexUpdateTriggers = IndexUpdateTriggers
            };

            TransactionalStorage = new TransactionalStorage(configuration, workContext.NotifyAboutWork);
            configuration.Container.SatisfyImportsOnce(TransactionalStorage);

            bool newDb;

            try
            {
                newDb = TransactionalStorage.Initialize();
            }
            catch (Exception)
            {
                TransactionalStorage.Dispose();
                throw;
            }

            IndexDefinitionStorage = new IndexDefinitionStorage(
                TransactionalStorage,
                configuration.DataDirectory,
                configuration.Container.GetExportedValues <AbstractViewGenerator>());
            IndexStorage = new IndexStorage(IndexDefinitionStorage, configuration);

            workContext.IndexStorage           = IndexStorage;
            workContext.TransactionaStorage    = TransactionalStorage;
            workContext.IndexDefinitionStorage = IndexDefinitionStorage;


            InitializeTriggers();
            ExecuteStartupTasks();

            if (!newDb)
            {
                return;
            }

            OnNewlyCreatedDatabase();
        }
コード例 #2
0
        protected Lucene.Net.Store.Directory OpenOrCreateLuceneDirectory(
            IndexDefinition indexDefinition,
            string indexName     = null,
            bool createIfMissing = true)
        {
            Lucene.Net.Store.Directory directory;
            if (indexDefinition.IsTemp || configuration.RunInMemory)
            {
                directory = new RAMDirectory();
                new IndexWriter(directory, dummyAnalyzer, IndexWriter.MaxFieldLength.UNLIMITED).Close();                 // creating index structure
            }
            else
            {
                var indexDirectory = indexName ?? IndexDefinitionStorage.FixupIndexName(indexDefinition.Name, path);
                var indexFullPath  = Path.Combine(path, MonoHttpUtility.UrlEncode(indexDirectory));
                directory = FSDirectory.Open(new DirectoryInfo(indexFullPath));

                if (!IndexReader.IndexExists(directory))
                {
                    if (createIfMissing == false)
                    {
                        throw new InvalidOperationException("Index does not exists: " + indexDirectory);
                    }

                    //creating index structure if we need to
                    new IndexWriter(directory, dummyAnalyzer, IndexWriter.MaxFieldLength.UNLIMITED).Close();
                }
                else
                {
                    if (directory.FileExists("write.lock"))                     // we had an unclean shutdown
                    {
                        if (configuration.ResetIndexOnUncleanShutdown)
                        {
                            throw new InvalidOperationException("Rude shutdown detected on: " + indexDirectory);
                        }

                        CheckIndexAndRecover(directory, indexDirectory);
                        IndexWriter.Unlock(directory);
                        directory.DeleteFile("write.lock");
                    }
                }
            }

            return(directory);
        }
コード例 #3
0
ファイル: QueryActions.cs プロジェクト: dkardach/ravendb
        private IEnumerable <RavenJObject> GetQueryResults(IndexQuery query, AbstractViewGenerator viewGenerator, DocumentRetriever docRetriever, IEnumerable <JsonDocument> results, List <string> transformerErrors, Action <double> loadingDocumentsFinish, Action <double> transformerFinish, bool showTimings, CancellationTokenSource tokenSource)
        {
            if (query.PageSize <= 0) // maybe they just want the stats?
            {
                return(Enumerable.Empty <RavenJObject>());
            }

            IndexingFunc transformFunc = null;

            // Check an explicitly declared one first
            if (string.IsNullOrEmpty(query.ResultsTransformer) == false)
            {
                var transformGenerator = IndexDefinitionStorage.GetTransformer(query.ResultsTransformer);

                if (transformGenerator != null && transformGenerator.TransformResultsDefinition != null)
                {
                    transformFunc = transformGenerator.TransformResultsDefinition;
                }
                else
                {
                    throw new InvalidOperationException("The transformer " + query.ResultsTransformer + " was not found");
                }
            }

            if (transformFunc == null)
            {
                var resultsWithoutTransformer = results.Select(x => x.ToJson());
                return(showTimings ? new TimedEnumerable <RavenJObject>(resultsWithoutTransformer, loadingDocumentsFinish) : resultsWithoutTransformer);
            }

            var dynamicJsonObjects = results.Select(x => new DynamicLuceneOrParentDocumntObject(docRetriever, x.ToJson()));
            var robustEnumerator   = new RobustEnumerator(tokenSource.Token, 100)
            {
                OnError =
                    (exception, o) =>
                    transformerErrors.Add(string.Format("Doc '{0}', Error: {1}", Index.TryGetDocKey(o),
                                                        exception.Message))
            };

            var resultsWithTransformer = robustEnumerator
                                         .RobustEnumeration(dynamicJsonObjects.Cast <object>().GetEnumerator(), transformFunc)
                                         .Select(JsonExtensions.ToJObject);

            return(showTimings ? new TimedEnumerable <RavenJObject>(resultsWithTransformer, transformerFinish) : resultsWithTransformer);
        }
コード例 #4
0
        public string PutIndex(string name, IndexDefinition definition)
        {
            switch (IndexDefinitionStorage.FindIndexCreationOptionsOptions(name, definition))
            {
            case IndexCreationOptions.Noop:
                return(name);

            case IndexCreationOptions.Update:
                // ensure that the code can compile
                new DynamicViewCompiler(name, definition, Extensions).GenerateInstance();
                DeleteIndex(name);
                break;
            }
            IndexDefinitionStorage.AddIndex(name, definition);
            IndexStorage.CreateIndexImplementation(name, definition);
            TransactionalStorage.Batch(actions => AddIndexAndEnqueueIndexingTasks(actions, name));
            return(name);
        }
コード例 #5
0
ファイル: IndexStorage.cs プロジェクト: stgwilli/ravendb
        protected Lucene.Net.Store.Directory OpenOrCreateLuceneDirectory(IndexDefinition indexDefinition, string indexName = null)
        {
            Lucene.Net.Store.Directory directory;
            if (indexDefinition.IsTemp || configuration.RunInMemory)
            {
                directory = new RAMDirectory();
            }
            else
            {
                var indexDirectory = indexName ?? IndexDefinitionStorage.FixupIndexName(indexDefinition.Name, path);
                directory = FSDirectory.Open(new DirectoryInfo(Path.Combine(path, MonoHttpUtility.UrlEncode(indexDirectory))));
            }

            //creating index structure if we need to
            new IndexWriter(directory, dummyAnalyzer, IndexWriter.MaxFieldLength.UNLIMITED).Close();

            return(directory);
        }
コード例 #6
0
        public void ResetIndex(string index)
        {
            index = IndexDefinitionStorage.FixupIndexName(index);
            var indexDefinition = IndexDefinitionStorage.GetIndexDefinition(index);

            if (indexDefinition == null)
            {
                throw new InvalidOperationException("There is no index named: " + index);
            }
            IndexStorage.DeleteIndex(index);
            IndexStorage.CreateIndexImplementation(indexDefinition);
            TransactionalStorage.Batch(actions =>
            {
                actions.Indexing.DeleteIndex(index);
                actions.Indexing.AddIndex(index, indexDefinition.IsMapReduce);
                workContext.ShouldNotifyAboutWork();
            });
        }
コード例 #7
0
        public IndexStorage(IndexDefinitionStorage indexDefinitionStorage, InMemoryRavenConfiguration configuration, DocumentDatabase documentDatabase)
        {
            try
            {
                this.indexDefinitionStorage = indexDefinitionStorage;
                this.configuration          = configuration;
                this.documentDatabase       = documentDatabase;
                path = configuration.IndexStoragePath;

                if (Directory.Exists(path) == false && configuration.RunInMemory == false)
                {
                    Directory.CreateDirectory(path);
                }


                if (configuration.RunInMemory == false)
                {
                    var crashMarkerPath = Path.Combine(path, "indexing.crash-marker");

                    if (File.Exists(crashMarkerPath))
                    {
                        // the only way this can happen is if we crashed because of a power outage
                        // in this case, we consider all open indexes to be corrupt and force them
                        // to be reset. This is because to get better perf, we don't flush the files to disk,
                        // so in the case of a power outage, we can't be sure that there wasn't still stuff in
                        // the OS buffer that wasn't written yet.
                        configuration.ResetIndexOnUncleanShutdown = true;
                    }

                    // The delete on close ensures that the only way this file will exists is if there was
                    // a power outage while the server was running.
                    crashMarker = File.Create(crashMarkerPath, 16, FileOptions.DeleteOnClose);
                }

                BackgroundTaskExecuter.Instance.ExecuteAll(documentDatabase.WorkContext,
                                                           indexDefinitionStorage.IndexNames, (indexName, _) => OpenIndexOnStartup(indexName));
            }
            catch
            {
                Dispose();
                throw;
            }
        }
コード例 #8
0
        internal void DeleteIndex(IndexDefinition instance, bool removeByNameMapping = true, bool clearErrors = true, bool removeIndexReplaceDocument = true)
        {
            using (IndexDefinitionStorage.TryRemoveIndexContext())
            {
                if (instance == null)
                {
                    return;
                }

                // Set up a flag to signal that this is something we're doing
                TransactionalStorage.Batch(actions => actions.Lists.Set("Raven/Indexes/PendingDeletion", instance.IndexId.ToString(CultureInfo.InvariantCulture), (RavenJObject.FromObject(new
                {
                    TimeOfOriginalDeletion = SystemTime.UtcNow,
                    instance.IndexId,
                    IndexName = instance.Name
                })), UuidType.Tasks));

                // Delete the main record synchronously
                IndexDefinitionStorage.RemoveIndex(instance.IndexId, removeByNameMapping);
                Database.IndexStorage.DeleteIndex(instance.IndexId);

                if (clearErrors)
                {
                    WorkContext.ClearErrorsFor(instance.Name);
                }

                if (removeIndexReplaceDocument && instance.IsSideBySideIndex)
                {
                    Database.Documents.Delete(Constants.IndexReplacePrefix + instance.Name, null, null);
                }

                // And delete the data in the background
                StartDeletingIndexDataAsync(instance.IndexId, instance.Name);

                // We raise the notification now because as far as we're concerned it is done *now*
                TransactionalStorage.ExecuteImmediatelyOrRegisterForSynchronization(() => Database.Notifications.RaiseNotifications(new IndexChangeNotification
                {
                    Name = instance.Name,
                    Type = IndexChangeTypes.IndexRemoved,
                }));
            }
        }
コード例 #9
0
        public string PutTransform(string name, TransformerDefinition definition)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }
            if (definition == null)
            {
                throw new ArgumentNullException("definition");
            }

            name = name.Trim();

            var existingDefinition = IndexDefinitionStorage.GetTransformerDefinition(name);

            if (existingDefinition != null && existingDefinition.Equals(definition))
            {
                return(name); // no op for the same transformer
            }
            var generator = IndexDefinitionStorage.CompileTransform(definition);

            if (existingDefinition != null)
            {
                IndexDefinitionStorage.RemoveTransformer(existingDefinition.TransfomerId);
            }

            TransactionalStorage.Batch(accessor =>
            {
                definition.TransfomerId = (int)Database.Documents.GetNextIdentityValueWithoutOverwritingOnExistingDocuments("TransformerId", accessor);
            });

            IndexDefinitionStorage.CreateAndPersistTransform(definition, generator);
            IndexDefinitionStorage.AddTransform(definition.TransfomerId, definition);

            TransactionalStorage.ExecuteImmediatelyOrRegisterForSynchronization(() => Database.Notifications.RaiseNotifications(new TransformerChangeNotification()
            {
                Name = name,
                Type = TransformerChangeTypes.TransformerAdded,
            }));

            return(name);
        }
コード例 #10
0
ファイル: QueryActions.cs プロジェクト: stvoidmain/ravendb
        public IEnumerable <string> QueryDocumentIds(string index, IndexQuery query, CancellationToken token, out bool stale)
        {
            var queryStat = AddToCurrentlyRunningQueryList(index, query);

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

                    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, token)
                                                     select queryResult.Key);
                });
                stale = isStale;
                return(loadedIds);
            }
            finally
            {
                RemoveFromCurrentlyRunningQueryList(index, queryStat);
            }
        }
コード例 #11
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);
     }
 }
コード例 #12
0
        public bool IndexHasChanged(string name, IndexDefinition definition)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }

            name = name.Trim();
            IsIndexNameValid(name);

            var existingIndex = IndexDefinitionStorage.GetIndexDefinition(name);

            if (existingIndex == null)
            {
                return(true);
            }

            var creationOption = FindIndexCreationOptions(definition, ref name);

            return(creationOption != IndexCreationOptions.Noop);
        }
コード例 #13
0
        internal void PutNewIndexIntoStorage(string name, IndexDefinition definition)
        {
            Debug.Assert(Database.IndexStorage != null);
            Debug.Assert(TransactionalStorage != null);
            Debug.Assert(WorkContext != null);

            TransactionalStorage.Batch(actions =>
            {
                definition.IndexId = (int)Database.Documents.GetNextIdentityValueWithoutOverwritingOnExistingDocuments("IndexId", actions, null);
                IndexDefinitionStorage.RegisterNewIndexInThisSession(name, definition);

                // this has to happen in this fashion so we will expose the in memory status after the commit, but
                // before the rest of the world is notified about this.

                IndexDefinitionStorage.CreateAndPersistIndex(definition);
                Database.IndexStorage.CreateIndexImplementation(definition);

                InvokeSuggestionIndexing(name, definition);

                actions.Indexing.AddIndex(definition.IndexId, definition.IsMapReduce);
            });

            if (name.Equals(Constants.DocumentsByEntityNameIndex, StringComparison.InvariantCultureIgnoreCase) == false &&
                Database.IndexStorage.HasIndex(Constants.DocumentsByEntityNameIndex))
            {
                // optimization of handling new index creation when the number of document in a database is significantly greater than
                // number of documents that this index applies to - let us use built-in RavenDocumentsByEntityName to get just appropriate documents

                var index = Database.IndexStorage.GetIndexInstance(definition.IndexId);
                TryApplyPrecomputedBatchForNewIndex(index, definition);
            }

            WorkContext.ShouldNotifyAboutWork(() => "PUT INDEX " + name);
            WorkContext.NotifyAboutWork();
            // The act of adding it here make it visible to other threads
            // we have to do it in this way so first we prepare all the elements of the
            // index, then we add it to the storage in a way that make it public
            IndexDefinitionStorage.AddIndex(definition.IndexId, definition);
        }
コード例 #14
0
        public IEnumerable <string> QueryDocumentIds(string index, IndexQuery query, out bool stale)
        {
            index = IndexDefinitionStorage.FixupIndexName(index);
            bool             isStale   = false;
            HashSet <string> loadedIds = null;

            TransactionalStorage.Batch(
                actions =>
            {
                isStale = actions.Staleness.IsIndexStale(index, query.Cutoff, null);
                var indexFailureInformation = actions.Indexing.GetFailureRate(index)
                ;
                if (indexFailureInformation.IsInvalidIndex)
                {
                    throw new IndexDisabledException(indexFailureInformation);
                }
                loadedIds = new HashSet <string>(from queryResult in IndexStorage.Query(index, query, result => true, new FieldsToFetch(null, AggregationOperation.None, Raven.Abstractions.Data.Constants.DocumentIdFieldName))
                                                 select queryResult.Key);
            });
            stale = isStale;
            return(loadedIds);
        }
コード例 #15
0
        public string PutIndex(string name, IndexDefinition definition)
        {
            definition.Name = name = IndexDefinitionStorage.FixupIndexName(name);
            switch (IndexDefinitionStorage.FindIndexCreationOptions(definition))
            {
            case IndexCreationOptions.Noop:
                return(name);

            case IndexCreationOptions.Update:
                // ensure that the code can compile
                new DynamicViewCompiler(name, definition, Extensions, IndexDefinitionStorage.IndexDefinitionsPath, Configuration).GenerateInstance();
                DeleteIndex(name);
                break;
            }
            IndexDefinitionStorage.AddIndex(definition);
            IndexStorage.CreateIndexImplementation(definition);
            TransactionalStorage.Batch(actions =>
            {
                actions.Indexing.AddIndex(name, definition.IsMapReduce);
                workContext.ShouldNotifyAboutWork();
            });
            return(name);
        }
コード例 #16
0
        public IndexStorage(IndexDefinitionStorage indexDefinitionStorage, RavenConfiguration configuration)
        {
            this.configuration = configuration;
            path = Path.Combine(configuration.DataDirectory, "Indexes");
            if (Directory.Exists(path) == false)
            {
                Directory.CreateDirectory(path);
            }

            foreach (var indexDirectory in indexDefinitionStorage.IndexNames)
            {
                log.DebugFormat("Loading saved index {0}", indexDirectory);

                var indexDefinition = indexDefinitionStorage.GetIndexDefinition(indexDirectory);
                if (indexDefinition == null)
                {
                    continue;
                }
                indexes.TryAdd(indexDirectory,
                               CreateIndexImplementation(indexDirectory, indexDefinition,
                                                         OpenOrCreateLuceneDirectory(indexDirectory)));
            }
        }
コード例 #17
0
        public void DeleteIndex(string name)
        {
            using (IndexDefinitionStorage.TryRemoveIndexContext())
            {
                var instance = IndexDefinitionStorage.GetIndexDefinition(name);
                if (instance == null)
                {
                    return;
                }

                // Set up a flag to signal that this is something we're doing
                TransactionalStorage.Batch(actions => actions.Lists.Set("Raven/Indexes/PendingDeletion", instance.IndexId.ToString(CultureInfo.InvariantCulture), (RavenJObject.FromObject(new
                {
                    TimeOfOriginalDeletion = SystemTime.UtcNow,
                    instance.IndexId
                })), UuidType.Tasks));

                // Delete the main record synchronously
                IndexDefinitionStorage.RemoveIndex(name);
                Database.IndexStorage.DeleteIndex(instance.IndexId);

                ConcurrentSet <string> _;
                WorkContext.DoNotTouchAgainIfMissingReferences.TryRemove(instance.IndexId, out _);
                WorkContext.ClearErrorsFor(name);

                // And delete the data in the background
                StartDeletingIndexDataAsync(instance.IndexId);

                // We raise the notification now because as far as we're concerned it is done *now*
                TransactionalStorage.ExecuteImmediatelyOrRegisterForSynchronization(() => Database.Notifications.RaiseNotifications(new IndexChangeNotification
                {
                    Name = name,
                    Type = IndexChangeTypes.IndexRemoved,
                }));
            }
        }
コード例 #18
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
            });
        }
コード例 #19
0
 public IndexDefinition GetIndexDefinition(string index)
 {
     index = IndexDefinitionStorage.FixupIndexName(index);
     return(IndexDefinitionStorage.GetIndexDefinition(index));
 }
コード例 #20
0
 public IndexDefinition GetIndexDefinition(string index)
 {
     return(IndexDefinitionStorage.GetIndexDefinition(index));
 }
コード例 #21
0
        public string[] PutIndexes(string[] names, IndexDefinition[] definitions, IndexingPriority[] priorities)
        {
            var createdIndexes = new List <string>();
            var prioritiesList = new List <IndexingPriority>();

            try
            {
                for (int i = 0; i < names.Length; i++)
                {
                    var name       = names[i];
                    var definition = definitions[i];
                    var priority   = priorities[i];
                    if (name == null)
                    {
                        throw new ArgumentNullException("names", "Names cannot contain null values");
                    }

                    IsIndexNameValid(name);

                    var existingIndex = IndexDefinitionStorage.GetIndexDefinition(name);

                    if (existingIndex != null)
                    {
                        switch (existingIndex.LockMode)
                        {
                        case IndexLockMode.SideBySide:
                            Log.Info("Index {0} not saved because it might be only updated by side-by-side index");
                            throw new InvalidOperationException("Can not overwrite locked index: " + name + ". This index can be only updated by side-by-side index.");

                        case IndexLockMode.LockedIgnore:
                            Log.Info("Index {0} not saved because it was lock (with ignore)", name);
                            continue;

                        case IndexLockMode.LockedError:
                            throw new InvalidOperationException("Can not overwrite locked index: " + name);
                        }
                    }

                    name = name.Trim();

                    if (name.Equals("dynamic", StringComparison.OrdinalIgnoreCase) ||
                        name.StartsWith("dynamic/", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new ArgumentException("Cannot use index name " + name + " because it clashes with reserved dynamic index names", "name");
                    }

                    if (name.Contains("//"))
                    {
                        throw new ArgumentException("Cannot use an index with // in the name, but got: " + name, "name");
                    }

                    AssertAnalyzersValid(definition);

                    switch (FindIndexCreationOptions(definition, ref name))
                    {
                    case IndexCreationOptions.Noop:
                        continue;

                    case IndexCreationOptions.UpdateWithoutUpdatingCompiledIndex:
                        // ensure that the code can compile
                        new DynamicViewCompiler(definition.Name, definition, Database.Extensions, IndexDefinitionStorage.IndexDefinitionsPath, Database.Configuration).GenerateInstance();
                        IndexDefinitionStorage.UpdateIndexDefinitionWithoutUpdatingCompiledIndex(definition);
                        break;

                    case IndexCreationOptions.Update:
                        // ensure that the code can compile
                        new DynamicViewCompiler(definition.Name, definition, Database.Extensions, IndexDefinitionStorage.IndexDefinitionsPath, Database.Configuration).GenerateInstance();
                        DeleteIndex(name);
                        break;
                    }

                    PutNewIndexIntoStorage(name, definition, true);

                    WorkContext.ClearErrorsFor(name);

                    TransactionalStorage.ExecuteImmediatelyOrRegisterForSynchronization(() => Database.Notifications.RaiseNotifications(new IndexChangeNotification
                    {
                        Name = name,
                        Type = IndexChangeTypes.IndexAdded,
                    }));

                    createdIndexes.Add(name);
                    prioritiesList.Add(priority);
                }

                var indexesIds = createdIndexes.Select(x => Database.IndexStorage.GetIndexInstance(x).indexId).ToArray();
                Database.TransactionalStorage.Batch(accessor => accessor.Indexing.SetIndexesPriority(indexesIds, prioritiesList.ToArray()));

                return(createdIndexes.ToArray());
            }
            catch (Exception e)
            {
                Log.WarnException("Could not create index batch", e);
                foreach (var index in createdIndexes)
                {
                    DeleteIndex(index);
                }
                throw;
            }
        }
コード例 #22
0
        internal Lucene.Net.Store.Directory MakeRAMDirectoryPhysical(RAMDirectory ramDir, string indexName)
        {
            var newDir = new LuceneCodecDirectory(Path.Combine(path, MonoHttpUtility.UrlEncode(IndexDefinitionStorage.FixupIndexName(indexName, path))), documentDatabase.IndexCodecs.OfType <AbstractIndexCodec>());

            Lucene.Net.Store.Directory.Copy(ramDir, newDir, true);
            return(newDir);
        }
コード例 #23
0
        public Etag GetDocuments(int start, int pageSize, Etag etag, CancellationToken token, Func <JsonDocument, bool> addDocument,
                                 string transformer = null, Dictionary <string, RavenJToken> transformerParameters = null, long?maxSize = null, TimeSpan?timeout = null)
        {
            Etag lastDocumentReadEtag = null;

            using (DocumentCacher.SkipSetDocumentsInDocumentCache())
                TransactionalStorage.Batch(actions =>
                {
                    AbstractTransformer storedTransformer = null;
                    if (transformer != null)
                    {
                        storedTransformer = IndexDefinitionStorage.GetTransformer(transformer);
                        if (storedTransformer == null)
                        {
                            throw new InvalidOperationException("No transformer with the name: " + transformer);
                        }
                    }

                    var returnedDocs = false;
                    while (true)
                    {
                        var documents = etag == null
                            ? actions.Documents.GetDocumentsByReverseUpdateOrder(start, pageSize)
                            : actions.Documents.GetDocumentsAfter(etag, pageSize, token, maxSize: maxSize, timeout: timeout);

                        var documentRetriever = new DocumentRetriever(Database.Configuration, actions, Database.ReadTriggers, transformerParameters);
                        var docCount          = 0;
                        var docCountOnLastAdd = 0;
                        foreach (var doc in documents)
                        {
                            docCount++;

                            token.ThrowIfCancellationRequested();

                            if (docCount - docCountOnLastAdd > 1000)
                            {
                                addDocument(null); // heartbeat
                            }

                            if (etag != null)
                            {
                                etag = doc.Etag;
                            }

                            JsonDocument.EnsureIdInMetadata(doc);

                            var nonAuthoritativeInformationBehavior = actions.InFlightStateSnapshot.GetNonAuthoritativeInformationBehavior <JsonDocument>(null, doc.Key);
                            var document = nonAuthoritativeInformationBehavior == null ? doc : nonAuthoritativeInformationBehavior(doc);

                            document = documentRetriever.ExecuteReadTriggers(document, null, ReadOperation.Load);
                            if (document == null)
                            {
                                continue;
                            }

                            returnedDocs = true;
                            Database.WorkContext.UpdateFoundWork();

                            document = TransformDocumentIfNeeded(document, storedTransformer, documentRetriever);

                            var canContinue = addDocument(document);
                            if (!canContinue)
                            {
                                break;
                            }

                            lastDocumentReadEtag = etag;

                            docCountOnLastAdd = docCount;
                        }

                        if (returnedDocs || docCount == 0)
                        {
                            break;
                        }

                        // No document was found that matches the requested criteria
                        // If we had a failure happen, we update the etag as we don't need to process those documents again (no matches there anyways).
                        if (lastDocumentReadEtag != null)
                        {
                            etag = lastDocumentReadEtag;
                        }

                        start += docCount;
                    }
                });

            return(lastDocumentReadEtag);
        }
コード例 #24
0
        public DocumentDatabase(InMemoryRavenConfiguration configuration)
        {
            ExternalState = new ConcurrentDictionary <string, object>();

            if (configuration.BackgroundTasksPriority != ThreadPriority.Normal)
            {
                backgroundTaskScheduler = new TaskSchedulerWithCustomPriority(
                    // we need a minimum of three task threads - one for indexing dispatch, one for tasks, one for indexing ops
                    Math.Max(3, configuration.MaxNumberOfParallelIndexTasks + 2),
                    configuration.BackgroundTasksPriority);
            }
            else
            {
                backgroundTaskScheduler = TaskScheduler.Current;
            }

            ExtensionsState = new ConcurrentDictionary <object, object>();
            Configuration   = configuration;

            configuration.Container.SatisfyImportsOnce(this);

            workContext = new WorkContext
            {
                IndexUpdateTriggers = IndexUpdateTriggers,
                ReadTriggers        = ReadTriggers
            };

            TransactionalStorage = configuration.CreateTransactionalStorage(workContext.HandleWorkNotifications);
            configuration.Container.SatisfyImportsOnce(TransactionalStorage);

            try
            {
                TransactionalStorage.Initialize(this);
            }
            catch (Exception)
            {
                TransactionalStorage.Dispose();
                throw;
            }

            TransactionalStorage.Batch(actions => currentEtagBase = actions.General.GetNextIdentityValue("Raven/Etag"));

            IndexDefinitionStorage = new IndexDefinitionStorage(
                configuration,
                TransactionalStorage,
                configuration.DataDirectory,
                configuration.Container.GetExportedValues <AbstractViewGenerator>(),
                Extensions);
            IndexStorage = new IndexStorage(IndexDefinitionStorage, configuration);

            workContext.Configuration          = configuration;
            workContext.IndexStorage           = IndexStorage;
            workContext.TransactionaStorage    = TransactionalStorage;
            workContext.IndexDefinitionStorage = IndexDefinitionStorage;


            try
            {
                InitializeTriggers();
                ExecuteStartupTasks();
            }
            catch (Exception)
            {
                Dispose();
                throw;
            }
        }
コード例 #25
0
        public void GetDocumentsWithIdStartingWith(string idPrefix, string matches, string exclude, int start, int pageSize,
                                                   CancellationToken token, ref int nextStart, Action <JsonDocument> addDoc,
                                                   string transformer = null, Dictionary <string, RavenJToken> transformerParameters = null,
                                                   string skipAfter   = null)
        {
            if (idPrefix == null)
            {
                throw new ArgumentNullException("idPrefix");
            }
            idPrefix = idPrefix.Trim();

            var canPerformRapidPagination = nextStart > 0 && start == nextStart;
            var actualStart       = canPerformRapidPagination ? start : 0;
            var addedDocs         = 0;
            var docCountOnLastAdd = 0;
            var matchedDocs       = 0;

            TransactionalStorage.Batch(
                actions =>
            {
                var docsToSkip = canPerformRapidPagination ? 0 : start;
                int docCount;

                AbstractTransformer storedTransformer = null;
                if (transformer != null)
                {
                    storedTransformer = IndexDefinitionStorage.GetTransformer(transformer);
                    if (storedTransformer == null)
                    {
                        throw new InvalidOperationException("No transformer with the name: " + transformer);
                    }
                }

                do
                {
                    Database.WorkContext.UpdateFoundWork();

                    docCount = 0;
                    var docs = actions.Documents.GetDocumentsWithIdStartingWith(idPrefix, actualStart, pageSize, string.IsNullOrEmpty(skipAfter) ? null : skipAfter);
                    var documentRetriever = new DocumentRetriever(Database.Configuration, actions, Database.ReadTriggers, transformerParameters);

                    foreach (var doc in docs)
                    {
                        token.ThrowIfCancellationRequested();
                        docCount++;
                        if (docCount - docCountOnLastAdd > 1000)
                        {
                            addDoc(null);     // heartbeat
                        }

                        var keyTest = doc.Key.Substring(idPrefix.Length);

                        if (!WildcardMatcher.Matches(matches, keyTest) || WildcardMatcher.MatchesExclusion(exclude, keyTest))
                        {
                            continue;
                        }

                        JsonDocument.EnsureIdInMetadata(doc);
                        var nonAuthoritativeInformationBehavior = actions.InFlightStateSnapshot.GetNonAuthoritativeInformationBehavior <JsonDocument>(null, doc.Key);

                        var document = nonAuthoritativeInformationBehavior != null ? nonAuthoritativeInformationBehavior(doc) : doc;
                        document     = documentRetriever.ExecuteReadTriggers(document, null, ReadOperation.Load);
                        if (document == null)
                        {
                            continue;
                        }

                        matchedDocs++;

                        if (matchedDocs <= docsToSkip)
                        {
                            continue;
                        }

                        token.ThrowIfCancellationRequested();

                        document = TransformDocumentIfNeeded(document, storedTransformer, documentRetriever);
                        addDoc(document);

                        addedDocs++;
                        docCountOnLastAdd = docCount;

                        if (addedDocs >= pageSize)
                        {
                            break;
                        }
                    }

                    actualStart += pageSize;
                } while (docCount > 0 && addedDocs < pageSize && actualStart > 0 && actualStart < int.MaxValue);
            });

            if (addedDocs != pageSize)
            {
                nextStart = start; // will mark as last page
            }
            else if (canPerformRapidPagination)
            {
                nextStart = start + matchedDocs;
            }
            else
            {
                nextStart = actualStart;
            }
        }
コード例 #26
0
        public string[] GetIndexFields(string index)
        {
            var abstractViewGenerator = IndexDefinitionStorage.GetViewGenerator(index);

            return(abstractViewGenerator == null ? new string[0] : abstractViewGenerator.Fields);
        }
コード例 #27
0
        public void GetDocumentsWithIdStartingWith(string idPrefix, string matches, string exclude, int start, int pageSize,
                                                   CancellationToken token, ref int nextStart, Action <RavenJObject> addDoc,
                                                   string transformer = null, Dictionary <string, RavenJToken> transformerParameters = null,
                                                   string skipAfter   = null)
        {
            if (idPrefix == null)
            {
                throw new ArgumentNullException("idPrefix");
            }
            idPrefix = idPrefix.Trim();

            var canPerformRapidPagination = nextStart > 0 && start == nextStart;
            var actualStart = canPerformRapidPagination ? start : 0;
            var addedDocs   = 0;
            var matchedDocs = 0;

            TransactionalStorage.Batch(
                actions =>
            {
                var docsToSkip = canPerformRapidPagination ? 0 : start;
                int docCount;

                AbstractTransformer storedTransformer = null;
                if (transformer != null)
                {
                    storedTransformer = IndexDefinitionStorage.GetTransformer(transformer);
                    if (storedTransformer == null)
                    {
                        throw new InvalidOperationException("No transformer with the name: " + transformer);
                    }
                }

                do
                {
                    docCount = 0;
                    var docs = actions.Documents.GetDocumentsWithIdStartingWith(idPrefix, actualStart, pageSize, string.IsNullOrEmpty(skipAfter) ? null : skipAfter);
                    var documentRetriever = new DocumentRetriever(actions, Database.ReadTriggers, Database.InFlightTransactionalState, transformerParameters);

                    foreach (var doc in docs)
                    {
                        token.ThrowIfCancellationRequested();
                        docCount++;
                        var keyTest = doc.Key.Substring(idPrefix.Length);

                        if (!WildcardMatcher.Matches(matches, keyTest) || WildcardMatcher.MatchesExclusion(exclude, keyTest))
                        {
                            continue;
                        }

                        DocumentRetriever.EnsureIdInMetadata(doc);
                        var nonAuthoritativeInformationBehavior = Database.InFlightTransactionalState.GetNonAuthoritativeInformationBehavior <JsonDocument>(null, doc.Key);

                        var document = nonAuthoritativeInformationBehavior != null ? nonAuthoritativeInformationBehavior(doc) : doc;
                        document     = documentRetriever.ExecuteReadTriggers(document, null, ReadOperation.Load);
                        if (document == null)
                        {
                            continue;
                        }

                        matchedDocs++;

                        if (matchedDocs <= docsToSkip)
                        {
                            continue;
                        }

                        token.ThrowIfCancellationRequested();

                        if (storedTransformer != null)
                        {
                            using (new CurrentTransformationScope(Database, documentRetriever))
                            {
                                var transformed =
                                    storedTransformer.TransformResultsDefinition(new[] { new DynamicJsonObject(document.ToJson()) })
                                    .Select(x => JsonExtensions.ToJObject(x))
                                    .ToArray();

                                if (transformed.Length == 0)
                                {
                                    throw new InvalidOperationException("The transform results function failed on a document: " + document.Key);
                                }

                                var transformedJsonDocument = new JsonDocument
                                {
                                    Etag = document.Etag.HashWith(storedTransformer.GetHashCodeBytes()).HashWith(documentRetriever.Etag),
                                    NonAuthoritativeInformation = document.NonAuthoritativeInformation,
                                    LastModified = document.LastModified,
                                    DataAsJson   = new RavenJObject {
                                        { "$values", new RavenJArray(transformed) }
                                    },
                                };

                                addDoc(transformedJsonDocument.ToJson());
                            }
                        }
                        else
                        {
                            addDoc(document.ToJson());
                        }

                        addedDocs++;

                        if (addedDocs >= pageSize)
                        {
                            break;
                        }
                    }

                    actualStart += pageSize;
                }while (docCount > 0 && addedDocs < pageSize && actualStart > 0 && actualStart < int.MaxValue);
            });

            if (addedDocs != pageSize)
            {
                nextStart = start; // will mark as last page
            }
            else if (canPerformRapidPagination)
            {
                nextStart = start + matchedDocs;
            }
            else
            {
                nextStart = actualStart;
            }
        }
コード例 #28
0
        private Action TryCreateTaskForApplyingPrecomputedBatchForNewIndex(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(null);
            }

            try
            {
                var cts = new CancellationTokenSource();

                var task = new Task(() =>
                {
                    try
                    {
                        ApplyPrecomputedBatchForNewIndex(index, generator, index.IsTestIndex == false ? Database.Configuration.MaxNumberOfItemsToProcessInSingleBatch : Database.Configuration.Indexing.MaxNumberOfItemsToProcessInTestIndexes, cts);
                    }
                    catch (Exception e)
                    {
                        Log.Warn("Could not apply precomputed batch for index " + index, e);
                    }
                    finally
                    {
                        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,
                            Payload = index.PublicName,
                            TaskType = TaskActions.PendingTaskType.NewIndexPrecomputedBatch
                        },
                            out id,
                            cts);
                    }
                    catch (Exception)
                    {
                        index.IsMapIndexingInProgress = false;
                        throw;
                    }
                });
            }
            catch (Exception)
            {
                index.IsMapIndexingInProgress = false;
                throw;
            }
        }
コード例 #29
0
        internal void PutNewIndexIntoStorage(string name, IndexDefinition definition, bool disableIndex = false)
        {
            Debug.Assert(Database.IndexStorage != null);
            Debug.Assert(TransactionalStorage != null);
            Debug.Assert(WorkContext != null);

            Index index = null;

            TransactionalStorage.Batch(actions =>
            {
                var maxId = 0;
                if (Database.IndexStorage.Indexes.Length > 0)
                {
                    maxId = Database.IndexStorage.Indexes.Max();
                }
                definition.IndexId = (int)Database.Documents.GetNextIdentityValueWithoutOverwritingOnExistingDocuments("IndexId", actions);
                if (definition.IndexId <= maxId)
                {
                    actions.General.SetIdentityValue("IndexId", maxId + 1);
                    definition.IndexId = (int)Database.Documents.GetNextIdentityValueWithoutOverwritingOnExistingDocuments("IndexId", actions);
                }


                IndexDefinitionStorage.RegisterNewIndexInThisSession(name, definition);

                // this has to happen in this fashion so we will expose the in memory status after the commit, but
                // before the rest of the world is notified about this.

                IndexDefinitionStorage.CreateAndPersistIndex(definition);
                Database.IndexStorage.CreateIndexImplementation(definition);
                index = Database.IndexStorage.GetIndexInstance(definition.IndexId);
                // If we execute multiple indexes at once and want to activate them all at once we will disable the index from the endpoint
                if (disableIndex)
                {
                    index.Priority = IndexingPriority.Disabled;
                }
                //ensure that we don't start indexing it right away, let the precomputation run first, if applicable
                index.IsMapIndexingInProgress = true;
                if (definition.IsTestIndex)
                {
                    index.MarkQueried();                     // test indexes should be mark queried, so the cleanup task would not delete them immediately
                }
                InvokeSuggestionIndexing(name, definition, index);

                actions.Indexing.AddIndex(definition.IndexId, definition.IsMapReduce);
            });

            Debug.Assert(index != null);

            Action precomputeTask = null;

            if (WorkContext.RunIndexing &&
                name.Equals(Constants.DocumentsByEntityNameIndex, StringComparison.InvariantCultureIgnoreCase) == false &&
                Database.IndexStorage.HasIndex(Constants.DocumentsByEntityNameIndex))
            {
                // optimization of handling new index creation when the number of document in a database is significantly greater than
                // number of documents that this index applies to - let us use built-in RavenDocumentsByEntityName to get just appropriate documents

                precomputeTask = TryCreateTaskForApplyingPrecomputedBatchForNewIndex(index, definition);
            }
            else
            {
                index.IsMapIndexingInProgress = false;        // we can't apply optimization, so we'll make it eligible for running normally
            }

            // The act of adding it here make it visible to other threads
            // we have to do it in this way so first we prepare all the elements of the
            // index, then we add it to the storage in a way that make it public
            IndexDefinitionStorage.AddIndex(definition.IndexId, definition);

            // we start the precomuteTask _after_ we finished adding the index
            if (precomputeTask != null)
            {
                precomputeTask();
            }

            WorkContext.ShouldNotifyAboutWork(() => "PUT INDEX " + name);
            WorkContext.NotifyAboutWork();
        }
コード例 #30
0
        public Etag GetIndexEtag(string indexName, Etag previousEtag, string resultTransformer = null)
        {
            Etag lastDocEtag     = Etag.Empty;
            Etag lastIndexedEtag = null;
            Etag lastReducedEtag = null;
            bool isStale         = false;
            int  touchCount      = 0;

            TransactionalStorage.Batch(accessor =>
            {
                var indexInstance = Database.IndexStorage.GetIndexInstance(indexName);
                if (indexInstance == null)
                {
                    return;
                }
                isStale = (indexInstance.IsMapIndexingInProgress) ||
                          accessor.Staleness.IsIndexStale(indexInstance.indexId, null, null);
                lastDocEtag    = accessor.Staleness.GetMostRecentDocumentEtag();
                var indexStats = accessor.Indexing.GetIndexStats(indexInstance.indexId);
                if (indexStats != null)
                {
                    lastReducedEtag = indexStats.LastReducedEtag;
                    lastIndexedEtag = indexStats.LastIndexedEtag;
                }
                touchCount = accessor.Staleness.GetIndexTouchCount(indexInstance.indexId);
            });


            var indexDefinition = GetIndexDefinition(indexName);

            if (indexDefinition == null)
            {
                return(Etag.Empty); // this ensures that we will get the normal reaction of IndexNotFound later on.
            }
            var list = new List <byte>();

            list.AddRange(indexDefinition.GetIndexHash());
            list.AddRange(Encoding.Unicode.GetBytes(indexName));
            if (string.IsNullOrWhiteSpace(resultTransformer) == false)
            {
                var abstractTransformer = IndexDefinitionStorage.GetTransformer(resultTransformer);
                if (abstractTransformer == null)
                {
                    throw new InvalidOperationException("The result transformer: " + resultTransformer + " was not found");
                }
                list.AddRange(abstractTransformer.GetHashCodeBytes());
            }
            list.AddRange(lastDocEtag.ToByteArray());
            list.AddRange(BitConverter.GetBytes(touchCount));
            list.AddRange(BitConverter.GetBytes(isStale));
            if (lastReducedEtag != null)
            {
                list.AddRange(lastReducedEtag.ToByteArray());
            }
            if (lastIndexedEtag != null)
            {
                list.AddRange(lastIndexedEtag.ToByteArray());
            }
            list.AddRange(BitConverter.GetBytes(UuidGenerator.LastDocumentTransactionEtag));

            var indexEtag = Etag.Parse(Encryptor.Current.Hash.Compute16(list.ToArray()));

            if (previousEtag != null && previousEtag != indexEtag)
            {
                // the index changed between the time when we got it and the time
                // we actually call this, we need to return something random so that
                // the next time we won't get 304

                return(Etag.InvalidEtag);
            }

            return(indexEtag);
        }