private void WriteDatabaseInfo(string databaseName, BlittableJsonReaderObject dbRecordBlittable, TransactionOperationContext context, AbstractBlittableJsonTextWriter writer) { var nodesTopology = new NodesTopology(); try { var online = ServerStore.DatabasesLandlord.DatabasesCache.TryGetValue(databaseName, out Task <DocumentDatabase> dbTask) && dbTask != null && dbTask.IsCompleted; var dbRecord = JsonDeserializationCluster.DatabaseRecord(dbRecordBlittable); var topology = dbRecord.Topology; var statuses = ServerStore.GetNodesStatuses(); if (topology != null) { nodesTopology.PriorityOrder = topology.PriorityOrder; var clusterTopology = ServerStore.GetClusterTopology(context); clusterTopology.ReplaceCurrentNodeUrlWithClientRequestedNodeUrlIfNecessary(ServerStore, HttpContext); foreach (var member in topology.Members) { if (dbRecord.DeletionInProgress != null && dbRecord.DeletionInProgress.ContainsKey(member)) { continue; } var url = clusterTopology.GetUrlFromTag(member); var node = new InternalReplication { Database = databaseName, NodeTag = member, Url = url }; nodesTopology.Members.Add(GetNodeId(node)); SetNodeStatus(topology, member, nodesTopology, statuses); } foreach (var promotable in topology.Promotables) { if (dbRecord.DeletionInProgress != null && dbRecord.DeletionInProgress.ContainsKey(promotable)) { continue; } topology.PredefinedMentors.TryGetValue(promotable, out var mentorCandidate); var node = GetNode(databaseName, clusterTopology, promotable, mentorCandidate, out var promotableTask); var mentor = topology.WhoseTaskIsIt(ServerStore.Engine.CurrentState, promotableTask, null); nodesTopology.Promotables.Add(GetNodeId(node, mentor)); SetNodeStatus(topology, promotable, nodesTopology, statuses); } foreach (var rehab in topology.Rehabs) { if (dbRecord.DeletionInProgress != null && dbRecord.DeletionInProgress.ContainsKey(rehab)) { continue; } var node = GetNode(databaseName, clusterTopology, rehab, null, out var promotableTask); var mentor = topology.WhoseTaskIsIt(ServerStore.Engine.CurrentState, promotableTask, null); nodesTopology.Rehabs.Add(GetNodeId(node, mentor)); SetNodeStatus(topology, rehab, nodesTopology, statuses); } } // Check for exceptions if (dbTask != null && dbTask.IsFaulted) { var exception = dbTask.Exception.ExtractSingleInnerException(); WriteFaultedDatabaseInfo(databaseName, nodesTopology, exception, context, writer); return; } var db = online ? dbTask.Result : null; var indexingStatus = db?.IndexStore?.Status; if (indexingStatus == null) { // Looking for disabled indexing flag inside the database settings for offline database status if (dbRecord.Settings.TryGetValue(RavenConfiguration.GetKey(x => x.Indexing.Disabled), out var val) && bool.TryParse(val, out var indexingDisabled) && indexingDisabled) { indexingStatus = IndexRunningStatus.Disabled; } } var disabled = dbRecord.Disabled; var studioEnvironment = StudioConfiguration.StudioEnvironment.None; if (dbRecord.Studio != null && !dbRecord.Studio.Disabled) { studioEnvironment = dbRecord.Studio.Environment; } if (online == false) { // if state of database is found in the cache we can continue if (ServerStore.DatabaseInfoCache.TryGet(databaseName, databaseInfoJson => { databaseInfoJson.Modifications = new DynamicJsonValue(databaseInfoJson) { [nameof(DatabaseInfo.Disabled)] = disabled, [nameof(DatabaseInfo.IndexingStatus)] = indexingStatus, [nameof(DatabaseInfo.NodesTopology)] = nodesTopology.ToJson(), [nameof(DatabaseInfo.DeletionInProgress)] = DynamicJsonValue.Convert(dbRecord.DeletionInProgress), [nameof(DatabaseInfo.Environment)] = studioEnvironment }; context.Write(writer, databaseInfoJson); })) { return; } // we won't find it if it is a new database or after a dirty shutdown, // so just report empty values then } var size = db?.GetSizeOnDisk() ?? (new Size(0), new Size(0)); var databaseInfo = new DatabaseInfo { Name = databaseName, Disabled = disabled, TotalSize = size.Data, TempBuffersSize = size.TempBuffers, IsAdmin = true, IsEncrypted = dbRecord.Encrypted, UpTime = online ? (TimeSpan?)GetUptime(db) : null, BackupInfo = GetBackupInfo(db, context), Alerts = db?.NotificationCenter.GetAlertCount() ?? 0, PerformanceHints = db?.NotificationCenter.GetPerformanceHintCount() ?? 0, RejectClients = false, LoadError = null, IndexingErrors = db?.IndexStore?.GetIndexes()?.Sum(index => index.GetErrorCount()) ?? 0, DocumentsCount = db?.DocumentsStorage.GetNumberOfDocuments() ?? 0, HasRevisionsConfiguration = db?.DocumentsStorage.RevisionsStorage.Configuration != null, HasExpirationConfiguration = (db?.ExpiredDocumentsCleaner?.ExpirationConfiguration?.Disabled ?? true) == false, HasRefreshConfiguration = (db?.ExpiredDocumentsCleaner?.RefreshConfiguration?.Disabled ?? true) == false, IndexesCount = db?.IndexStore?.GetIndexes()?.Count() ?? 0, IndexingStatus = indexingStatus ?? IndexRunningStatus.Running, Environment = studioEnvironment, NodesTopology = nodesTopology, ReplicationFactor = topology?.ReplicationFactor ?? -1, DynamicNodesDistribution = topology?.DynamicNodesDistribution ?? false, DeletionInProgress = dbRecord.DeletionInProgress }; var doc = databaseInfo.ToJson(); context.Write(writer, doc); } catch (Exception e) { if (Logger.IsInfoEnabled) { Logger.Info($"Failed to get database info for: {databaseName}", e); } WriteFaultedDatabaseInfo(databaseName, nodesTopology, e, context, writer); } }
public override object FromRemote(object remoteResult) { return(JsonDeserializationCluster.CompareExchangeResult((BlittableJsonReaderObject)remoteResult)); }
private void WriteDatabaseInfo(string databaseName, BlittableJsonReaderObject dbRecordBlittable, TransactionOperationContext context, BlittableJsonTextWriter writer) { var online = ServerStore.DatabasesLandlord.DatabasesCache.TryGetValue(databaseName, out Task <DocumentDatabase> dbTask) && dbTask != null && dbTask.IsCompleted; // Check for exceptions if (dbTask != null && dbTask.IsFaulted) { WriteFaultedDatabaseInfo(context, writer, dbTask, databaseName); return; } var dbRecord = JsonDeserializationCluster.DatabaseRecord(dbRecordBlittable); var db = online ? dbTask.Result : null; var indexingStatus = db?.IndexStore.Status ?? IndexRunningStatus.Running; // Looking for disabled indexing flag inside the database settings for offline database status if (dbRecord.Settings.TryGetValue(RavenConfiguration.GetKey(x => x.Indexing.Disabled), out var val) && val == "true") { indexingStatus = IndexRunningStatus.Disabled; } var disabled = dbRecord.Disabled; var topology = dbRecord.Topology; var clusterTopology = ServerStore.GetClusterTopology(context); var nodesTopology = new NodesTopology(); if (topology != null) { foreach (var member in topology.Members) { var url = clusterTopology.GetUrlFromTag(member); var node = new InternalReplication { Database = databaseName, NodeTag = member, Url = url }; nodesTopology.Members.Add(GetNodeId(node)); SetNodeStatus(topology, member, nodesTopology); } foreach (var promotable in topology.Promotables) { var node = GetNode(databaseName, clusterTopology, promotable, out var promotableTask); var mentor = topology.WhoseTaskIsIt(promotableTask, ServerStore.IsPassive()); nodesTopology.Promotables.Add(GetNodeId(node, mentor)); SetNodeStatus(topology, promotable, nodesTopology); } foreach (var rehab in topology.Rehabs) { var node = GetNode(databaseName, clusterTopology, rehab, out var promotableTask); var mentor = topology.WhoseTaskIsIt(promotableTask, ServerStore.IsPassive()); nodesTopology.Rehabs.Add(GetNodeId(node, mentor)); SetNodeStatus(topology, rehab, nodesTopology); } } if (online == false) { // If state of database is found in the cache we can continue if (ServerStore.DatabaseInfoCache.TryWriteOfflineDatabaseStatusToRequest( context, writer, databaseName, disabled, indexingStatus, nodesTopology)) { return; } // We won't find it if it is a new database or after a dirty shutdown, so just report empty values then } var size = new Size(GetTotalSize(db)); var databaseInfo = new DatabaseInfo { Name = databaseName, Disabled = disabled, TotalSize = size, IsAdmin = true, //TODO: implement me! IsEncrypted = dbRecord.Encrypted, UpTime = online ? (TimeSpan?)GetUptime(db) : null, BackupInfo = GetBackupInfo(db), Alerts = db?.NotificationCenter.GetAlertCount() ?? 0, RejectClients = false, //TODO: implement me! LoadError = null, IndexingErrors = db?.IndexStore.GetIndexes().Sum(index => index.GetErrorCount()) ?? 0, DocumentsCount = db?.DocumentsStorage.GetNumberOfDocuments() ?? 0, HasRevisionsConfiguration = db?.DocumentsStorage.RevisionsStorage.Configuration != null, HasExpirationConfiguration = db?.ExpiredDocumentsCleaner != null, IndexesCount = db?.IndexStore.GetIndexes().Count() ?? 0, IndexingStatus = indexingStatus, NodesTopology = nodesTopology, ReplicationFactor = topology?.ReplicationFactor ?? -1, DynamicNodesDistribution = topology?.DynamicNodesDistribution ?? false }; var doc = databaseInfo.ToJson(); context.Write(writer, doc); }
public Task GetTopology() { var name = GetQueryStringValueAndAssertIfSingleAndNotEmpty("name"); using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context)) { var dbId = Constants.Documents.Prefix + name; using (context.OpenReadTransaction()) using (var dbBlit = ServerStore.Cluster.Read(context, dbId, out long _)) { if (TryGetAllowedDbs(name, out var _, requireAdmin: false) == false) { return(Task.CompletedTask); } if (dbBlit == null) { // here we return 503 so clients will try to failover to another server // if this is a newly created db that we haven't been notified about it yet HttpContext.Response.StatusCode = (int)HttpStatusCode.ServiceUnavailable; HttpContext.Response.Headers["Database-Missing"] = name; using (var writer = new BlittableJsonTextWriter(context, HttpContext.Response.Body)) { context.Write(writer, new DynamicJsonValue { ["Type"] = "Error", ["Message"] = "Database " + name + " wasn't found" }); } return(Task.CompletedTask); } var clusterTopology = ServerStore.GetClusterTopology(context); var dbRecord = JsonDeserializationCluster.DatabaseRecord(dbBlit); using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream())) { context.Write(writer, new DynamicJsonValue { [nameof(Topology.Nodes)] = new DynamicJsonArray( dbRecord.Topology.Members.Select(x => new DynamicJsonValue { [nameof(ServerNode.Url)] = GetUrl(x, clusterTopology), [nameof(ServerNode.ClusterTag)] = x, [nameof(ServerNode.ServerRole)] = ServerNode.Role.Member, [nameof(ServerNode.Database)] = dbRecord.DatabaseName }) .Concat(dbRecord.Topology.Rehabs.Select(x => new DynamicJsonValue { [nameof(ServerNode.Url)] = GetUrl(x, clusterTopology), [nameof(ServerNode.ClusterTag)] = x, [nameof(ServerNode.Database)] = dbRecord.DatabaseName, [nameof(ServerNode.ServerRole)] = ServerNode.Role.Rehab }) ) ), [nameof(Topology.Etag)] = dbRecord.Topology.Stamp.Index }); } } } return(Task.CompletedTask); }
public override void SetResponse(JsonOperationContext context, BlittableJsonReaderObject response, bool fromCache) { Result = JsonDeserializationCluster.DatabaseRecord(response); }
public DatabaseRecord GetDatabaseRecord() { var databaseRecord = new DatabaseRecord(); ReadObject(reader => { if (reader.TryGet(nameof(databaseRecord.Revisions), out BlittableJsonReaderObject revisions) && revisions != null) { try { databaseRecord.Revisions = JsonDeserializationCluster.RevisionsConfiguration(revisions); } catch (Exception e) { if (_log.IsInfoEnabled) { _log.Info("Wasn't able to import the reivions configuration from smuggler file. Skiping.", e); } } } if (reader.TryGet(nameof(databaseRecord.Expiration), out BlittableJsonReaderObject expiration) && expiration != null) { try { databaseRecord.Expiration = JsonDeserializationCluster.ExpirationConfiguration(expiration); } catch (Exception e) { if (_log.IsInfoEnabled) { _log.Info("Wasn't able to import the expiration configuration from smuggler file. Skiping.", e); } } } if (reader.TryGet(nameof(databaseRecord.RavenConnectionStrings), out BlittableJsonReaderObject ravenConnectionStrings) && ravenConnectionStrings != null) { try { foreach (var connectionName in ravenConnectionStrings.GetPropertyNames()) { if (ravenConnectionStrings.TryGet(connectionName, out BlittableJsonReaderObject connection) == false) { if (_log.IsInfoEnabled) { _log.Info($"Wasn't able to import the RavenDB connection string {connectionName} from smuggler file. Skiping."); } continue; } var connectionString = JsonDeserializationCluster.RavenConnectionString(connection); databaseRecord.RavenConnectionStrings[connectionString.Name] = connectionString; } } catch (Exception e) { databaseRecord.RavenConnectionStrings.Clear(); if (_log.IsInfoEnabled) { _log.Info("Wasn't able to import the RavenDB connection strings from smuggler file. Skiping.", e); } } } if (reader.TryGet(nameof(databaseRecord.SqlConnectionStrings), out BlittableJsonReaderObject sqlConnectionStrings) && sqlConnectionStrings != null) { try { foreach (var connectionName in sqlConnectionStrings.GetPropertyNames()) { if (ravenConnectionStrings.TryGet(connectionName, out BlittableJsonReaderObject connection) == false) { if (_log.IsInfoEnabled) { _log.Info($"Wasn't able to import the SQL connection string {connectionName} from smuggler file. Skiping."); } continue; } var connectionString = JsonDeserializationCluster.SqlConnectionString(connection); databaseRecord.SqlConnectionStrings[connectionString.Name] = connectionString; } } catch (Exception e) { databaseRecord.SqlConnectionStrings.Clear(); if (_log.IsInfoEnabled) { _log.Info("Wasn't able to import the SQL connection strings from smuggler file. Skiping.", e); } } } if (reader.TryGet(nameof(databaseRecord.Client), out BlittableJsonReaderObject client) && client != null) { try { databaseRecord.Client = JsonDeserializationCluster.ClientConfiguration(expiration); } catch (Exception e) { if (_log.IsInfoEnabled) { _log.Info("Wasn't able to import the client configuration from smuggler file. Skiping.", e); } } } }); return(databaseRecord); }
public Task GetServerWideTasksForStudio() { var taskName = GetStringQueryString("name", required: false); var typeAsString = GetStringQueryString("type", required: false); var tryParse = Enum.TryParse(typeAsString, out OngoingTaskType type); if (typeAsString != null && tryParse == false) { throw new ArgumentException($"{typeAsString} is unknown task type."); } using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context)) using (context.OpenReadTransaction()) using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream())) { var result = new ServerWideTasksResult(); var blittables = ServerStore.Cluster.GetServerWideConfigurations(context, OngoingTaskType.Backup, taskName); foreach (var blittable in blittables) { var configuration = JsonDeserializationCluster.ServerWideBackupConfiguration(blittable); if (taskName != null && type == OngoingTaskType.Backup && string.Equals(taskName, configuration.Name) == false) { continue; } result.Tasks.Add(new ServerWideTasksResult.ServerWideBackupTask { TaskId = configuration.TaskId, TaskName = configuration.Name, TaskState = configuration.Disabled ? OngoingTaskState.Disabled : OngoingTaskState.Enabled, ExcludedDatabases = configuration.ExcludedDatabases, BackupType = configuration.BackupType, RetentionPolicy = configuration.RetentionPolicy, BackupDestinations = configuration.GetDestinations(), IsEncrypted = configuration.BackupEncryptionSettings != null && configuration.BackupEncryptionSettings.EncryptionMode != EncryptionMode.None }); } blittables = ServerStore.Cluster.GetServerWideConfigurations(context, OngoingTaskType.Replication, taskName); foreach (var blittable in blittables) { var configuration = JsonDeserializationCluster.ServerWideExternalReplication(blittable); if (taskName != null && type == OngoingTaskType.Replication && string.Equals(taskName, configuration.Name) == false) { continue; } result.Tasks.Add(new ServerWideTasksResult.ServerWideExternalReplicationTask { TaskId = configuration.TaskId, TaskName = configuration.Name, TaskState = configuration.Disabled ? OngoingTaskState.Disabled : OngoingTaskState.Enabled, ExcludedDatabases = configuration.ExcludedDatabases, TopologyDiscoveryUrls = configuration.TopologyDiscoveryUrls, DelayReplicationFor = configuration.DelayReplicationFor, }); } context.Write(writer, result.ToJson()); writer.Flush(); return(Task.CompletedTask); } }
public bool Update(UpdateStep step) { var dbs = new List <string>(); const string dbKey = "db/"; var identities = step.ReadTx.ReadTree(ClusterStateMachine.Identities); step.WriteTx.DeleteTree(ClusterStateMachine.Identities); using (var items = step.ReadTx.OpenTable(ClusterStateMachine.ItemsSchema, ClusterStateMachine.Items)) using (Slice.From(step.ReadTx.Allocator, dbKey, out Slice loweredPrefix)) { foreach (var result in items.SeekByPrimaryKeyPrefix(loweredPrefix, Slices.Empty, 0)) { dbs.Add(ClusterStateMachine.GetCurrentItemKey(result.Value).Substring(dbKey.Length)); } } step.WriteTx.CreateTree(ClusterStateMachine.CompareExchangeIndex); foreach (var db in dbs) { if (identities != null) { Slice.From(step.WriteTx.Allocator, "Identities", out var identitySlice); ClusterStateMachine.IdentitiesSchema.Create(step.WriteTx, identitySlice, 32); var writeTable = step.WriteTx.OpenTable(ClusterStateMachine.IdentitiesSchema, identitySlice); using (Slice.From(step.ReadTx.Allocator, $"{dbKey}{db.ToLowerInvariant()}/identities/", out var identityPrefix)) { using (var it = identities.Iterate(prefetch: false)) { it.SetRequiredPrefix(identityPrefix); if (it.Seek(identityPrefix)) { do { var key = it.CurrentKey; var keyAsString = key.ToString(); // old identity key var value = it.CreateReaderForCurrent().ReadLittleEndianInt64(); var newKey = keyAsString.Substring(identityPrefix.ToString().Length); // write to new identities schema GetKeyAndPrefixIndexSlices(step.ReadTx.Allocator, db, $"{newKey}", 0L, out var keyTuple, out var indexTuple); using (keyTuple.Scope) using (indexTuple.Scope) using (Slice.External(step.ReadTx.Allocator, keyTuple.Buffer.Ptr, keyTuple.Buffer.Length, out var keySlice)) using (Slice.External(step.ReadTx.Allocator, indexTuple.Buffer.Ptr, indexTuple.Buffer.Length, out var prefixIndexSlice)) { using (writeTable.Allocate(out var write)) { write.Add(keySlice); write.Add(value); write.Add(0L); write.Add(prefixIndexSlice); writeTable.Set(write); } } } while (it.MoveNext()); } } } } // update db backup status var dbLower = db.ToLowerInvariant(); using (var items = step.WriteTx.OpenTable(ClusterStateMachine.ItemsSchema, ClusterStateMachine.Items)) using (Slice.From(step.ReadTx.Allocator, $"{dbKey}{dbLower}", out Slice lowerKey)) using (var ctx = JsonOperationContext.ShortTermSingleUse()) { var(databaseRecordJson, _) = GetBjroAndIndex(ctx, items, lowerKey); var databaseRecord = JsonDeserializationCluster.DatabaseRecord(databaseRecordJson); if (databaseRecord == null) { continue; } foreach (var pb in databaseRecord.PeriodicBackups) { var pbItemName = PeriodicBackupStatus.GenerateItemName(db, pb.TaskId); using (Slice.From(step.WriteTx.Allocator, pbItemName, out Slice pbsSlice)) using (Slice.From(step.WriteTx.Allocator, pbItemName.ToLowerInvariant(), out Slice pbsSliceLower)) { var(singleBackupStatus, index) = GetBjroAndIndex(ctx, items, pbsSlice); if (singleBackupStatus == null) { continue; } if (singleBackupStatus.TryGet(nameof(PeriodicBackupStatus.LocalBackup), out BlittableJsonReaderObject localBackup) == false || singleBackupStatus.TryGet(nameof(PeriodicBackupStatus.LastRaftIndex), out BlittableJsonReaderObject lastRaftIndexBlittable) == false) { continue; } if (localBackup.TryGet(nameof(PeriodicBackupStatus.LastIncrementalBackup), out DateTime? lastIncrementalBackupDate) == false || lastRaftIndexBlittable.TryGet(nameof(PeriodicBackupStatus.LastEtag), out long?lastRaftIndex) == false) { continue; } if (lastIncrementalBackupDate == null || lastRaftIndex == null) { continue; } var myLastRaftIndex = new LastRaftIndex { LastEtag = 0L }; singleBackupStatus.Modifications = new DynamicJsonValue { [nameof(PeriodicBackupStatus.LastRaftIndex)] = myLastRaftIndex.ToJson() }; using (var old = singleBackupStatus) { singleBackupStatus = ctx.ReadObject(singleBackupStatus, pbItemName); } using (items.Allocate(out var builder)) { builder.Add(pbsSliceLower); builder.Add(pbsSlice); builder.Add(singleBackupStatus.BasePointer, singleBackupStatus.Size); builder.Add(index); items.Set(builder); } } } } } return(true); }
public bool Update(UpdateStep step) { var dbs = new List <string>(); const string dbKey = "db/"; var newIdentitiesSchema = new TableSchema() .DefineKey(new TableSchema.SchemaIndexDef { StartIndex = (int)ClusterStateMachine.IdentitiesTable.Key, Count = 1 }).DefineIndex(new TableSchema.SchemaIndexDef { StartIndex = (int)ClusterStateMachine.IdentitiesTable.KeyIndex, Count = 1, IsGlobal = true, Name = ClusterStateMachine.IdentitiesIndex }); using (var items = step.ReadTx.OpenTable(ClusterStateMachine.ItemsSchema, ClusterStateMachine.Items)) using (Slice.From(step.ReadTx.Allocator, dbKey, out Slice loweredPrefix)) { foreach (var result in items.SeekByPrimaryKeyPrefix(loweredPrefix, Slices.Empty, 0)) { dbs.Add(ClusterStateMachine.GetCurrentItemKey(result.Value).Substring(dbKey.Length)); } } foreach (var db in dbs) { var dbPrefixLowered = $"{db.ToLowerInvariant()}/"; // update IdentitiesSchema var readIdentitiesTable = step.ReadTx.OpenTable(ClusterStateMachine.IdentitiesSchema, ClusterStateMachine.Identities); if (readIdentitiesTable != null) { using (Slice.From(step.ReadTx.Allocator, dbPrefixLowered, out var keyPrefix)) { var writeIdentitiesTable = step.WriteTx.OpenTable(newIdentitiesSchema, ClusterStateMachine.Identities); foreach (var item in readIdentitiesTable.SeekByPrimaryKeyPrefix(keyPrefix, Slices.Empty, 0)) { var value = TableValueToLong((int)ClusterStateMachine.IdentitiesTable.Value, ref item.Value.Reader); var index = TableValueToLong((int)ClusterStateMachine.IdentitiesTable.Index, ref item.Value.Reader); // if value is not 0 than we come from v4.2 and could have wrong index value if (index != 0) { using (GetPrefixIndexSlices(step.ReadTx.Allocator, db, 0L, out var buffer)) using (Slice.External(step.WriteTx.Allocator, buffer.Ptr, buffer.Length, out var prefixIndexSlice)) using (writeIdentitiesTable.Allocate(out TableValueBuilder write)) { write.Add(item.Key); write.Add(value); write.Add(0L); write.Add(prefixIndexSlice); writeIdentitiesTable.Set(write); } } } } } // update db backup status var dbLower = db.ToLowerInvariant(); using (var items = step.WriteTx.OpenTable(ClusterStateMachine.ItemsSchema, ClusterStateMachine.Items)) using (Slice.From(step.ReadTx.Allocator, $"{dbKey}{dbLower}", out Slice lowerKey)) using (var ctx = JsonOperationContext.ShortTermSingleUse()) { var(databaseRecordJson, _) = GetBjroAndIndex(ctx, items, lowerKey); var databaseRecord = JsonDeserializationCluster.DatabaseRecord(databaseRecordJson); if (databaseRecord == null) { continue; } foreach (var pb in databaseRecord.PeriodicBackups) { var pbItemName = PeriodicBackupStatus.GenerateItemName(db, pb.TaskId); using (Slice.From(step.WriteTx.Allocator, pbItemName, out Slice pbsSlice)) using (Slice.From(step.WriteTx.Allocator, pbItemName.ToLowerInvariant(), out Slice pbsSliceLower)) { var(singleBackupStatus, index) = GetBjroAndIndex(ctx, items, pbsSlice); if (singleBackupStatus == null) { continue; } if (singleBackupStatus.TryGet(nameof(PeriodicBackupStatus.LocalBackup), out BlittableJsonReaderObject localBackup) == false || singleBackupStatus.TryGet(nameof(PeriodicBackupStatus.LastRaftIndex), out BlittableJsonReaderObject lastRaftIndexBlittable) == false) { continue; } if (localBackup.TryGet(nameof(PeriodicBackupStatus.LastIncrementalBackup), out DateTime? lastIncrementalBackupDate) == false || lastRaftIndexBlittable.TryGet(nameof(PeriodicBackupStatus.LastEtag), out long?lastRaftIndex) == false) { continue; } if (lastIncrementalBackupDate == null || lastRaftIndex == null) { continue; } // already set in from12 before if (lastRaftIndex == 0) { continue; } var myLastRaftIndex = new LastRaftIndex { LastEtag = 0L }; singleBackupStatus.Modifications = new DynamicJsonValue { [nameof(PeriodicBackupStatus.LastRaftIndex)] = myLastRaftIndex.ToJson() }; using (var old = singleBackupStatus) { singleBackupStatus = ctx.ReadObject(singleBackupStatus, pbItemName); } using (items.Allocate(out var builder)) { builder.Add(pbsSliceLower); builder.Add(pbsSlice); builder.Add(singleBackupStatus.BasePointer, singleBackupStatus.Size); builder.Add(index); items.Set(builder); } } } } } return(true); }