예제 #1
0
        public Task DetailedStats()
        {
            using (var context = QueryOperationContext.Allocate(Database, needsServerContext: true))
            {
                var stats = new DetailedDatabaseStatistics();

                FillDatabaseStatistics(stats, context);

                using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext serverContext))
                    using (serverContext.OpenReadTransaction())
                    {
                        stats.CountOfIdentities                = ServerStore.Cluster.GetNumberOfIdentities(serverContext, Database.Name);
                        stats.CountOfCompareExchange           = ServerStore.Cluster.GetNumberOfCompareExchange(serverContext, Database.Name);
                        stats.CountOfCompareExchangeTombstones = ServerStore.Cluster.GetNumberOfCompareExchangeTombstones(serverContext, Database.Name);
                    }

                using (var writer = new BlittableJsonTextWriter(context.Documents, ResponseBodyStream()))
                    writer.WriteDetailedDatabaseStatistics(context.Documents, stats);
            }

            return(Task.CompletedTask);
        }
예제 #2
0
        public async Task Patch()
        {
            var queryContext = QueryOperationContext.Allocate(Database); // we don't dispose this as operation is async

            try
            {
                var reader = await queryContext.Documents.ReadForMemoryAsync(RequestBodyStream(), "queries/patch");

                if (reader == null)
                {
                    throw new BadRequestException("Missing JSON content.");
                }
                if (reader.TryGet("Query", out BlittableJsonReaderObject queryJson) == false || queryJson == null)
                {
                    throw new BadRequestException("Missing 'Query' property.");
                }

                var query = IndexQueryServerSide.Create(HttpContext, queryJson, Database.QueryMetadataCache, null, queryType: QueryType.Update);

                query.DisableAutoIndexCreation = GetBoolValueQueryString("disableAutoIndexCreation", false) ?? false;

                if (TrafficWatchManager.HasRegisteredClients)
                {
                    TrafficWatchQuery(query);
                }

                var patch = new PatchRequest(query.Metadata.GetUpdateBody(query.QueryParameters), PatchRequestType.Patch, query.Metadata.DeclaredFunctions);

                await ExecuteQueryOperation(query,
                                            (runner, options, onProgress, token) => runner.ExecutePatchQuery(
                                                query, options, patch, query.QueryParameters, queryContext, onProgress, token),
                                            queryContext, Operations.Operations.OperationType.UpdateByQuery);
            }
            catch
            {
                queryContext.Dispose();
                throw;
            }
        }
예제 #3
0
        public async Task StayInRehabWithErrorIndexes2()
        {
            var(node, leader) = await CreateRaftCluster(3, watcherCluster : true);

            var database = GetDatabaseName();

            await CreateDatabaseInClusterInner(new DatabaseRecord(database), 3, leader.WebUrl, null);

            using (var store = new DocumentStore
            {
                Database = database,
                Urls = new[] { leader.WebUrl }
            }.Initialize())
            {
                var documentDatabase = await Servers[2].ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(database);
                var result           = store.Maintenance.Send(new PutIndexesOperation(new[] { new IndexDefinition
                                                                                              {
                                                                                                  Maps = { "from user in docs.Users select new { user.Name }" },
                                                                                                  Name = "MyIndex"
                                                                                              } }));
                var indexResult = result[0];
                await WaitForRaftIndexToBeAppliedInCluster(indexResult.RaftCommandIndex, TimeSpan.FromSeconds(15));

                var index = documentDatabase.IndexStore.GetIndex("MyIndex");
                index.SetState(IndexState.Error);

                using (var session = store.OpenSession())
                {
                    session.Store(new User()
                    {
                        Name = "Toli"
                    }, "user/1");
                    session.SaveChanges();
                }

                using (var context = QueryOperationContext.Allocate(documentDatabase, index))
                    using (context.OpenReadTransaction())
                    {
                        var state = index.GetIndexingState(context);
                        Assert.Equal(0, state.LastProcessedEtag);
                    }

                var record = await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(store.Database));

                record.Topology.Members.Remove(Servers[2].ServerStore.NodeTag);
                record.Topology.Rehabs.Add(Servers[2].ServerStore.NodeTag);
                await store.Maintenance.Server.SendAsync(new UpdateDatabaseOperation(record, record.Etag));

                var rehabs = await WaitForValueAsync(async() => await GetRehabCount(store, store.Database), 1);

                Assert.Equal(1, rehabs);

                var val = await WaitForValueAsync(async() => await GetMembersCount(store, database), 2);

                Assert.Equal(2, val);

                val = await WaitForValueAsync(async() => await GetMembersCount(store, store.Database), 3);

                Assert.Equal(2, val);
            }
        }
예제 #4
0
        protected override async Task DoWork()
        {
            await WaitOrThrowOperationCanceled(_notificationCenter.Options.DatabaseStatsThrottle);

            Stats    current;
            DateTime?lastIndexingErrorTime = null;

            var indexes               = _database.IndexStore.GetIndexes().ToList();
            var needsServerContext    = indexes.Any(x => x.Definition.HasCompareExchange);
            var staleIndexes          = 0;
            var countOfIndexingErrors = 0L;

            using (var context = QueryOperationContext.Allocate(_database, needsServerContext))
                using (context.OpenReadTransaction())
                {
                    // ReSharper disable once LoopCanBeConvertedToQuery
                    foreach (var index in indexes)
                    {
                        if (index.IsStale(context))
                        {
                            staleIndexes++;
                        }

                        var errorCount = index.GetErrorCount();

                        if (errorCount > 0)
                        {
                            var lastError = index.GetLastIndexingErrorTime();
                            if (lastError != null)
                            {
                                if (lastIndexingErrorTime == null || lastError > lastIndexingErrorTime)
                                {
                                    lastIndexingErrorTime = lastError;
                                }
                            }
                        }
                        countOfIndexingErrors += errorCount;
                    }

                    current = new Stats
                    {
                        CountOfConflicts      = _database.DocumentsStorage.ConflictsStorage.GetNumberOfDocumentsConflicts(context.Documents),
                        CountOfDocuments      = _database.DocumentsStorage.GetNumberOfDocuments(context.Documents),
                        CountOfIndexes        = indexes.Count,
                        CountOfStaleIndexes   = staleIndexes,
                        CountOfIndexingErrors = countOfIndexingErrors,
                        LastEtag           = DocumentsStorage.ReadLastEtag(context.Documents.Transaction.InnerTransaction),
                        GlobalChangeVector = DocumentsStorage.GetDatabaseChangeVector(context.Documents)
                    };
                    current.Collections = _database.DocumentsStorage.GetCollections(context.Documents)
                                          .ToDictionary(x => x.Name, x => new DatabaseStatsChanged.ModifiedCollection(x.Name, x.Count, _database.DocumentsStorage.GetLastDocumentChangeVector(context.Documents.Transaction.InnerTransaction, context.Documents, x.Name)));
                }

            if (_latest != null && _latest.Equals(current))
            {
                return;
            }

            var modifiedCollections = _latest == null?current.Collections.Values.ToList() : ExtractModifiedCollections(current);

            _notificationCenter.Add(DatabaseStatsChanged.Create(
                                        _database.Name,
                                        current.CountOfConflicts,
                                        current.CountOfDocuments,
                                        current.CountOfIndexes,
                                        current.CountOfStaleIndexes,
                                        current.GlobalChangeVector,
                                        current.LastEtag,
                                        current.CountOfIndexingErrors,
                                        lastIndexingErrorTime,
                                        modifiedCollections));

            _latest = current;
        }
예제 #5
0
        public async Task NotInRehabWithDisabledIndexes3()
        {
            var(node, leader) = await CreateRaftCluster(3, watcherCluster : true);

            var database = GetDatabaseName();

            await CreateDatabaseInClusterInner(new DatabaseRecord(database), 3, leader.WebUrl, null);

            using (var store = new DocumentStore
            {
                Database = database,
                Urls = new[] { leader.WebUrl }
            }.Initialize())
            {
                var documentDatabase = await Servers[2].ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(database);
                var result           = store.Maintenance.Send(new PutIndexesOperation(new[] { new IndexDefinition
                                                                                              {
                                                                                                  Maps = { "from user in docs.Users select new { user.Name }" },
                                                                                                  Name = "MyIndex"
                                                                                              } }));
                var indexResult = result[0];
                await Cluster.WaitForRaftIndexToBeAppliedInClusterAsync(indexResult.RaftCommandIndex, TimeSpan.FromSeconds(15));

                await RollingIndexesClusterTests.WaitForRollingIndex(database, "MyIndex", Servers[2]);

                var index = documentDatabase.IndexStore.GetIndex("MyIndex");
                index.SetState(IndexState.Error);

                using (var session = store.OpenSession())
                {
                    session.Store(new User()
                    {
                        Name = "Toli"
                    }, "user/1");
                    session.SaveChanges();
                }

                index.SetState(IndexState.Disabled);

                using (var context = QueryOperationContext.Allocate(documentDatabase, index))
                    using (context.OpenReadTransaction())
                    {
                        var state = index.GetIndexingState(context);
                        Assert.Equal(0, state.LastProcessedEtag);
                    }

                var record = await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(store.Database));

                record.Topology.Members.Remove(Servers[2].ServerStore.NodeTag);
                record.Topology.Rehabs.Add(Servers[2].ServerStore.NodeTag);
                await store.Maintenance.Server.SendAsync(new UpdateDatabaseOperation(record, record.Etag));

                await WaitAndAssertForValueAsync(async() => await RavenDB_15588.GetMembersAndRehabsCount(store), expectedVal : (MembersCount : 2, RehabsCount : 1));

                // assert that Servers[2] is promoted back to Member
                var expectedVal = (MembersCount : 3, RehabsCount : 0);
                var val         = await WaitForPredicateAsync(async() => await RavenDB_15588.GetMembersAndRehabsCount(store), expectedVal : expectedVal);

                Assert.True(val.Equals(expectedVal), await GetDecisionsForDatabase(
                                new StringBuilder("Failed on asserting Members and Rehabs count.")
                                .AppendLine($"Expected {expectedVal}, got : {val}")));
            }
        }
예제 #6
0
        public async Task Stats()
        {
            var name = GetStringQueryString("name", required: false);

            using (var context = QueryOperationContext.Allocate(Database, needsServerContext: true))
                await using (var writer = new AsyncBlittableJsonTextWriter(context.Documents, ResponseBodyStream()))
                {
                    IndexStats[] indexStats;
                    using (context.OpenReadTransaction())
                    {
                        if (string.IsNullOrEmpty(name))
                        {
                            indexStats = Database.IndexStore
                                         .GetIndexes()
                                         .OrderBy(x => x.Name)
                                         .Select(x =>
                            {
                                try
                                {
                                    return(x.GetStats(calculateLag: true, calculateStaleness: true, calculateMemoryStats: true, queryContext: context));
                                }
                                catch (Exception e)
                                {
                                    if (Logger.IsOperationsEnabled)
                                    {
                                        Logger.Operations($"Failed to get stats of '{x.Name}' index", e);
                                    }

                                    try
                                    {
                                        Database.NotificationCenter.Add(AlertRaised.Create(Database.Name, $"Failed to get stats of '{x.Name}' index",
                                                                                           $"Exception was thrown on getting stats of '{x.Name}' index",
                                                                                           AlertType.Indexing_CouldNotGetStats, NotificationSeverity.Error, key: x.Name, details: new ExceptionDetails(e)));
                                    }
                                    catch (Exception addAlertException)
                                    {
                                        if (Logger.IsOperationsEnabled && addAlertException.IsOutOfMemory() == false && addAlertException.IsRavenDiskFullException() == false)
                                        {
                                            Logger.Operations($"Failed to add alert when getting error on retrieving stats of '{x.Name}' index", addAlertException);
                                        }
                                    }

                                    var state = x.State;

                                    if (e.IsOutOfMemory() == false && e.IsRavenDiskFullException() == false)
                                    {
                                        try
                                        {
                                            state = IndexState.Error;
                                            x.SetState(state, inMemoryOnly: true);
                                        }
                                        catch (Exception ex)
                                        {
                                            if (Logger.IsOperationsEnabled)
                                            {
                                                Logger.Operations($"Failed to change state of '{x.Name}' index to error after encountering exception when getting its stats.",
                                                                  ex);
                                            }
                                        }
                                    }

                                    return(new IndexStats
                                    {
                                        Name = x.Name,
                                        Type = x.Type,
                                        State = state,
                                        Status = x.Status,
                                        LockMode = x.Definition.LockMode,
                                        Priority = x.Definition.Priority,
                                    });
                                }
                            })
                                         .ToArray();
                        }
                        else
                        {
                            var index = Database.IndexStore.GetIndex(name);
                            if (index == null)
                            {
                                HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
                                return;
                            }

                            indexStats = new[] { index.GetStats(calculateLag: true, calculateStaleness: true, calculateMemoryStats: true, queryContext: context) };
                        }
                    }

                    writer.WriteStartObject();

                    writer.WriteArray(context.Documents, "Results", indexStats, (w, c, stats) => w.WriteIndexStats(context.Documents, stats));

                    writer.WriteEndObject();
                }
        }
예제 #7
0
        public async Task StreamQueryGet()
        {
            // ReSharper disable once ArgumentsStyleLiteral
            using (var tracker = new RequestTimeTracker(HttpContext, Logger, Database, "StreamQuery", doPerformanceHintIfTooLong: false))
                using (var token = CreateTimeLimitedQueryToken())
                    using (var queryContext = QueryOperationContext.Allocate(Database))
                    {
                        var    documentId    = GetStringQueryString("fromDocument", false);
                        string overrideQuery = null;
                        if (string.IsNullOrEmpty(documentId) == false)
                        {
                            Document document;
                            using (queryContext.OpenReadTransaction())
                            {
                                document = Database.DocumentsStorage.Get(queryContext.Documents, documentId);
                                if (document == null)
                                {
                                    throw new DocumentDoesNotExistException($"Was request to stream a query taken from {documentId} document, but it does not exist.");
                                }
                                if (document.Data.TryGet("Query", out overrideQuery) == false)
                                {
                                    throw new MissingFieldException($"Expected {documentId} to have a property named 'Query' of type 'String' but couldn't locate such property.");
                                }
                            }
                        }
                        var query           = IndexQueryServerSide.Create(HttpContext, GetStart(), GetPageSize(), queryContext.Documents, tracker, overrideQuery);
                        var format          = GetStringQueryString("format", false);
                        var debug           = GetStringQueryString("debug", false);
                        var properties      = GetStringValuesQueryString("field", false);
                        var propertiesArray = properties.Count == 0 ? null : properties.ToArray();
                        // set the exported file name prefix
                        var fileNamePrefix = query.Metadata.IsCollectionQuery ? query.Metadata.CollectionName + "_collection" : "query_result";
                        fileNamePrefix = $"{Database.Name}_{fileNamePrefix}";
                        if (string.IsNullOrWhiteSpace(debug) == false)
                        {
                            if (string.Equals(debug, "entries", StringComparison.OrdinalIgnoreCase))
                            {
                                using (var writer = GetIndexEntriesQueryResultWriter(format, HttpContext.Response, ResponseBodyStream(), propertiesArray, fileNamePrefix))
                                {
                                    try
                                    {
                                        await Database.QueryRunner.ExecuteStreamIndexEntriesQuery(query, queryContext, HttpContext.Response, writer, token).ConfigureAwait(false);
                                    }
                                    catch (IndexDoesNotExistException)
                                    {
                                        HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
                                        writer.WriteError($"Index {query.Metadata.IndexName} does not exist");
                                    }
                                }
                            }
                            else
                            {
                                ThrowUnsupportedException($"You have selected {debug} debug mode, which is not supported.");
                            }
                        }
                        else
                        {
                            using (var writer = GetQueryResultWriter(format, HttpContext.Response, queryContext.Documents, ResponseBodyStream(), propertiesArray, fileNamePrefix))
                            {
                                try
                                {
                                    await Database.QueryRunner.ExecuteStreamQuery(query, queryContext, HttpContext.Response, writer, token).ConfigureAwait(false);
                                }
                                catch (IndexDoesNotExistException)
                                {
                                    HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
                                    writer.WriteError($"Index {query.Metadata.IndexName} does not exist");
                                }
                                catch (Exception e)
                                {
                                    try
                                    {
                                        writer.WriteError($"Failed to execute stream query. Error: {e}");
                                    }
                                    catch (Exception ie)
                                    {
                                        if (Logger.IsOperationsEnabled)
                                        {
                                            Logger.Operations($"Failed to write error. Error: {e}", ie);
                                        }
                                    }

                                    throw;
                                }
                            }
                        }
                    }
        }
예제 #8
0
        public async Task StreamQueryPost()
        {
            // ReSharper disable once ArgumentsStyleLiteral
            using (var tracker = new RequestTimeTracker(HttpContext, Logger, Database, "StreamQuery", doPerformanceHintIfTooLong: false))
                using (var token = CreateTimeLimitedQueryToken())
                    using (var queryContext = QueryOperationContext.Allocate(Database))
                    {
                        var stream    = TryGetRequestFromStream("ExportOptions") ?? RequestBodyStream();
                        var queryJson = await queryContext.Documents.ReadForMemoryAsync(stream, "index/query");

                        var query = IndexQueryServerSide.Create(HttpContext, queryJson, Database.QueryMetadataCache, tracker);

                        if (TrafficWatchManager.HasRegisteredClients)
                        {
                            var sb = new StringBuilder();
                            // append stringBuilder with the query
                            sb.Append(query.Query);
                            // if query got parameters append with parameters
                            if (query.QueryParameters != null && query.QueryParameters.Count > 0)
                            {
                                sb.AppendLine().Append(query.QueryParameters);
                            }
                            AddStringToHttpContext(sb.ToString(), TrafficWatchChangeType.Streams);
                        }

                        var format          = GetStringQueryString("format", false);
                        var debug           = GetStringQueryString("debug", false);
                        var properties      = GetStringValuesQueryString("field", false);
                        var propertiesArray = properties.Count == 0 ? null : properties.ToArray();

                        // set the exported file name prefix
                        var fileNamePrefix = query.Metadata.IsCollectionQuery ? query.Metadata.CollectionName + "_collection" : "query_result";
                        fileNamePrefix = $"{Database.Name}_{fileNamePrefix}";
                        if (string.IsNullOrWhiteSpace(debug) == false)
                        {
                            if (string.Equals(debug, "entries", StringComparison.OrdinalIgnoreCase))
                            {
                                using (var writer = GetIndexEntriesQueryResultWriter(format, HttpContext.Response, ResponseBodyStream(), propertiesArray, fileNamePrefix))
                                {
                                    try
                                    {
                                        await Database.QueryRunner.ExecuteStreamIndexEntriesQuery(query, queryContext, HttpContext.Response, writer, token).ConfigureAwait(false);
                                    }
                                    catch (IndexDoesNotExistException)
                                    {
                                        HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
                                        writer.WriteError($"Index {query.Metadata.IndexName} does not exist");
                                    }
                                }
                            }
                            else
                            {
                                ThrowUnsupportedException($"You have selected {debug} debug mode, which is not supported.");
                            }
                        }
                        else
                        {
                            using (var writer = GetQueryResultWriter(format, HttpContext.Response, queryContext.Documents, ResponseBodyStream(), propertiesArray, fileNamePrefix))
                            {
                                try
                                {
                                    await Database.QueryRunner.ExecuteStreamQuery(query, queryContext, HttpContext.Response, writer, token).ConfigureAwait(false);
                                }
                                catch (IndexDoesNotExistException)
                                {
                                    HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
                                    writer.WriteError($"Index {query.Metadata.IndexName} does not exist");
                                }
                            }
                        }
                    }
        }
        private Dictionary <string, DatabaseStatusReport> CollectDatabaseInformation(TransactionOperationContext ctx, Dictionary <string, DatabaseStatusReport> prevReport)
        {
            var result = new Dictionary <string, DatabaseStatusReport>();

            foreach (var dbName in _server.Cluster.GetDatabaseNames(ctx))
            {
                if (_token.IsCancellationRequested)
                {
                    return(result);
                }

                var report = new DatabaseStatusReport
                {
                    Name     = dbName,
                    NodeName = _server.NodeTag
                };

                if (_server.DatabasesLandlord.DatabasesCache.TryGetValue(dbName, out var dbTask, out var details) == false)
                {
                    DatabaseTopology topology;
                    using (var rawRecord = _server.Cluster.ReadRawDatabaseRecord(ctx, dbName))
                    {
                        if (rawRecord == null)
                        {
                            continue; // Database does not exists in this server
                        }

                        topology = rawRecord.Topology;
                    }

                    if (topology == null)
                    {
                        continue;
                    }

                    if (topology.RelevantFor(_server.NodeTag) == false)
                    {
                        continue;
                    }

                    report.Status  = DatabaseStatus.Unloaded;
                    result[dbName] = report;
                    continue;
                }

                report.UpTime = SystemTime.UtcNow - details.InCacheSince;

                if (dbTask.IsFaulted)
                {
                    var extractSingleInnerException = dbTask.Exception.ExtractSingleInnerException();
                    if (Equals(extractSingleInnerException.Data[DatabasesLandlord.DoNotRemove], true))
                    {
                        report.Status  = DatabaseStatus.Unloaded;
                        result[dbName] = report;
                        continue;
                    }
                }

                if (dbTask.IsCanceled || dbTask.IsFaulted)
                {
                    report.Status  = DatabaseStatus.Faulted;
                    report.Error   = dbTask.Exception.ToString();
                    result[dbName] = report;
                    continue;
                }

                if (dbTask.IsCompleted == false)
                {
                    report.Status  = DatabaseStatus.Loading;
                    result[dbName] = report;
                    continue;
                }

                var dbInstance  = dbTask.Result;
                var currentHash = dbInstance.GetEnvironmentsHash();
                report.EnvironmentsHash = currentHash;

                var documentsStorage = dbInstance.DocumentsStorage;
                var indexStorage     = dbInstance.IndexStore;

                if (dbInstance.DatabaseShutdown.IsCancellationRequested)
                {
                    report.Status  = DatabaseStatus.Shutdown;
                    result[dbName] = report;
                    continue;
                }

                report.Status = DatabaseStatus.Loaded;
                try
                {
                    var now = dbInstance.Time.GetUtcNow();
                    FillReplicationInfo(dbInstance, report);

                    prevReport.TryGetValue(dbName, out var prevDatabaseReport);
                    if (SupportedFeatures.Heartbeats.SendChangesOnly &&
                        prevDatabaseReport != null && prevDatabaseReport.EnvironmentsHash == currentHash)
                    {
                        report.Status  = DatabaseStatus.NoChange;
                        result[dbName] = report;
                        continue;
                    }

                    using (var context = QueryOperationContext.Allocate(dbInstance, needsServerContext: true))
                    {
                        FillDocumentsInfo(prevDatabaseReport, dbInstance, report, context.Documents, documentsStorage);
                        FillClusterTransactionInfo(report, dbInstance);

                        if (indexStorage != null)
                        {
                            foreach (var index in indexStorage.GetIndexes())
                            {
                                DatabaseStatusReport.ObservedIndexStatus stat = null;
                                if (prevDatabaseReport?.LastIndexStats.TryGetValue(index.Name, out stat) == true && stat?.LastTransactionId == index.LastTransactionId)
                                {
                                    report.LastIndexStats[index.Name] = stat;
                                    continue;
                                }

                                using (context.OpenReadTransaction())
                                {
                                    FillIndexInfo(index, context, now, report);
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    report.EnvironmentsHash = 0; // on error we should do the complete report collaction path
                    report.Error            = e.ToString();
                }

                result[dbName] = report;
            }

            return(result);
        }