public async Task DefineHub() { if (ResourceNameValidator.IsValidResourceName(Database.Name, ServerStore.Configuration.Core.DataDirectory.FullPath, out string errorMessage) == false) { throw new BadRequestException(errorMessage); } ServerStore.LicenseManager.AssertCanAddPullReplicationAsHub(); PullReplicationDefinition pullReplication = null; await DatabaseConfigurations((_, databaseName, blittableJson, guid) => { pullReplication = JsonDeserializationClient.PullReplicationDefinition(blittableJson); pullReplication.Validate(ServerStore.Server.Certificate?.Certificate != null); var updatePullReplication = new UpdatePullReplicationAsHubCommand(databaseName, guid) { Definition = pullReplication }; return(ServerStore.SendToLeaderAsync(updatePullReplication)); }, "update-hub-pull-replication", GetRaftRequestIdFromQuery(), fillJson : (json, _, index) => { json[nameof(OngoingTask.TaskId)] = pullReplication.TaskId == 0 ? index : pullReplication.TaskId; }, statusCode : HttpStatusCode.Created); }
public override string UpdateDatabaseRecord(DatabaseRecord record, long etag) { if (Definition.TaskId == 0) { Definition.TaskId = etag; } else { PullReplicationDefinition.RemoveHub(record.HubPullReplications, Definition.TaskId); } record.EnsureTaskNameIsNotUsed(Definition.Name); record.HubPullReplications.Add(Definition); return(null); }
public async Task DisablePullReplicationOnHub() { DebuggerAttachedTimeout.DisableLongTimespan = true; var definitionName = $"pull-replication {GetDatabaseName()}"; var timeout = 10_000; using (var sink = GetDocumentStore()) using (var hub = GetDocumentStore()) { var pullDefinition = new PullReplicationDefinition(definitionName); var saveResult = await hub.Maintenance.ForDatabase(hub.Database).SendAsync(new PutPullReplicationAsHubOperation(pullDefinition)); using (var main = hub.OpenSession()) { main.Store(new User(), "users/1"); main.SaveChanges(); } await SetupPullReplicationAsync(definitionName, sink, hub); Assert.True(WaitForDocument(sink, "users/1", timeout), sink.Identifier); var db = await Databases.GetDocumentDatabaseInstanceFor(sink); var removedOnSink = new ManualResetEventSlim(); db.ReplicationLoader.IncomingReplicationRemoved += _ => removedOnSink.Set(); pullDefinition.Disabled = true; pullDefinition.TaskId = saveResult.TaskId; await hub.Maintenance.ForDatabase(hub.Database).SendAsync(new PutPullReplicationAsHubOperation(pullDefinition)); Assert.True(removedOnSink.Wait(timeout)); using (var main = hub.OpenSession()) { main.Store(new User(), "users/2"); main.SaveChanges(); } Assert.False(WaitForDocument(sink, "users/2", timeout), sink.Identifier); pullDefinition.Disabled = false; pullDefinition.TaskId = saveResult.TaskId; await hub.Maintenance.ForDatabase(hub.Database).SendAsync(new PutPullReplicationAsHubOperation(pullDefinition)); Assert.True(WaitForDocument(sink, "users/2", timeout), sink.Identifier); } }
private List <string> GetResponsibleNodes(DatabaseTopology topology, string databaseGroupId, PullReplicationDefinition pullReplication) { var list = new List <string>(); // we distribute connections to have load balancing when many sinks are connected. // this is the hub cluster, so we make the decision which node will do the pull replication only once and only here, // for that we create a dummy IDatabaseTask. var mentorNodeTask = new PullNodeTask { Mentor = pullReplication.MentorNode, DatabaseGroupId = databaseGroupId }; while (topology.Members.Count > 0) { var next = topology.WhoseTaskIsIt(ServerStore.CurrentRachisState, mentorNodeTask, null); list.Add(next); topology.Members.Remove(next); } return(list); }