private ClusterDescription RemoveServer(ClusterDescription clusterDescription, EndPoint endPoint, string reason) { IClusterableServer server; var stopwatch = new Stopwatch(); lock (_serversLock) { server = _servers.SingleOrDefault(x => EndPointHelper.Equals(x.EndPoint, endPoint)); if (server == null) { return(clusterDescription); } if (_removingServerEventHandler != null) { _removingServerEventHandler(new ClusterRemovingServerEvent(server.ServerId, reason)); } stopwatch.Start(); _servers.Remove(server); } server.DescriptionChanged -= ServerDescriptionChangedHandler; server.Dispose(); stopwatch.Stop(); if (_removedServerEventHandler != null) { _removedServerEventHandler(new ClusterRemovedServerEvent(server.ServerId, reason, stopwatch.Elapsed)); } return(clusterDescription.WithoutServerDescription(endPoint)); }
/// <inheritdoc/> public bool Equals(ServerDescription other) { if (object.ReferenceEquals(other, null) || other.GetType() != typeof(ServerDescription)) { return(false); } return (_averageRoundTripTime == other._averageRoundTripTime && object.Equals(_canonicalEndPoint, other._canonicalEndPoint) && object.Equals(_electionId, other._electionId) && EndPointHelper.Equals(_endPoint, other._endPoint) && object.Equals(_heartbeatException, other._heartbeatException) && _heartbeatInterval == other._heartbeatInterval && _lastUpdateTimestamp == other._lastUpdateTimestamp && _lastWriteTimestamp == other._lastWriteTimestamp && _logicalSessionTimeout == other._logicalSessionTimeout && _maxBatchCount == other._maxBatchCount && _maxDocumentSize == other._maxDocumentSize && _maxMessageSize == other._maxMessageSize && _maxWireDocumentSize == other._maxWireDocumentSize && object.Equals(_replicaSetConfig, other._replicaSetConfig) && _serverId.Equals(other._serverId) && _state == other._state && object.Equals(_tags, other._tags) && _type == other._type && object.Equals(_version, other._version) && object.Equals(_wireVersionRange, other._wireVersionRange)); }
internal MongoServerInstance GetServerInstance(EndPoint endPoint) { lock (_serverLock) { return(_serverInstances.FirstOrDefault(i => EndPointHelper.Equals(i.EndPoint, endPoint))); } }
public bool Equals(ServerDescription x, ServerDescription y) { var lastUpdateTimestampDelta = Math.Abs((x.LastUpdateTimestamp - y.LastUpdateTimestamp).TotalMilliseconds); var tolerance = 1000.0; // 1 second return (x.AverageRoundTripTime.Equals(y.AverageRoundTripTime) && object.Equals(x.CanonicalEndPoint, y.CanonicalEndPoint) && object.Equals(x.ElectionId, y.ElectionId) && EndPointHelper.Equals(x.EndPoint, y.EndPoint) && object.Equals(x.HeartbeatException, y.HeartbeatException) && x.HeartbeatInterval.Equals(y.HeartbeatInterval) && lastUpdateTimestampDelta <= tolerance && x.LastWriteTimestamp.Equals(y.LastWriteTimestamp) && x.MaxBatchCount.Equals(y.MaxBatchCount) && x.MaxDocumentSize.Equals(y.MaxDocumentSize) && x.MaxMessageSize.Equals(y.MaxMessageSize) && x.MaxWireDocumentSize.Equals(y.MaxWireDocumentSize) && object.Equals(x.ReplicaSetConfig, y.ReplicaSetConfig) && x.ServerId.Equals(y.ServerId) && x.State.Equals(y.State) && object.Equals(x.Tags, y.Tags) && x.Type.Equals(y.Type) && #pragma warning disable CS0618 // Type or member is obsolete object.Equals(x.Version, y.Version) && #pragma warning restore CS0618 // Type or member is obsolete object.Equals(x.WireVersionRange, y.WireVersionRange)); }
public async Task Misbehaved_async_method_should_not_deadlock_server_selection() { RequireServer.Check().ClusterType(ClusterType.ReplicaSet); // note: the code below deadlocks because await StartSessionAsync continues when UpdateClusterDescription in Cluster called TrySetResult after finding the secondary // but then the sync call to RunCommand blocks waiting for a primary and the call to TrySetResult never returns // which in turn prevents SDAM from unwinding back to process the next queued heartbeat event so the primary is never found var primary = CoreTestConfiguration.Cluster.Description.Servers.Where(s => s.Type == ServerType.ReplicaSetPrimary).Single(); void clusterConfigurator(ClusterBuilder builder) { builder.Subscribe((ServerHeartbeatSucceededEvent heartbeatEvent) => { // ensure that the primary heartbeat is the last to be processed by introducing a small artificial delay if (EndPointHelper.Equals(heartbeatEvent.ConnectionId.ServerId.EndPoint, primary.EndPoint)) { Thread.Sleep(TimeSpan.FromSeconds(1)); } }); } using (var client = DriverTestConfiguration.CreateDisposableClient(clusterConfigurator)) { using (var session = await client.StartSessionAsync().ConfigureAwait(false)) { var adminDatabase = client.GetDatabase("admin"); adminDatabase.RunCommand <BsonDocument>(session, "{ ping : 1 }"); // this async method is misbehaving by calling a blocking sync method } } }
private void ProcessServerDescriptionChanged(ServerDescriptionChangedEventArgs args) { var newServers = new List <IClusterableServer>(); lock (_updateClusterDescriptionLock) { var newServerDescription = args.NewServerDescription; var newClusterDescription = Description; if (!_servers.Any(x => EndPointHelper.Equals(x.EndPoint, newServerDescription.EndPoint))) { return; } if (newServerDescription.State == ServerState.Disconnected) { newClusterDescription = newClusterDescription.WithServerDescription(newServerDescription); } else { if (IsServerValidForCluster(newClusterDescription.Type, Settings.ConnectionMode, newServerDescription.Type)) { if (newClusterDescription.Type == ClusterType.Unknown) { newClusterDescription = newClusterDescription.WithType(newServerDescription.Type.ToClusterType()); } switch (newClusterDescription.Type) { case ClusterType.Standalone: newClusterDescription = ProcessStandaloneChange(newClusterDescription, args); break; case ClusterType.ReplicaSet: newClusterDescription = ProcessReplicaSetChange(newClusterDescription, args, newServers); break; case ClusterType.Sharded: newClusterDescription = ProcessShardedChange(newClusterDescription, args); break; default: throw new MongoInternalException("Unexpected cluster type."); } } else { var reason = $"The server {newServerDescription.EndPoint} with type {newServerDescription.Type} is not valid for cluster type {newClusterDescription.Type}."; newClusterDescription = RemoveServer(newClusterDescription, newServerDescription.EndPoint, reason); } } UpdateClusterDescription(newClusterDescription); } foreach (var server in newServers) { server.Initialize(); } }
// methods /// <inheritdoc/> public IEnumerable <ServerDescription> SelectServers(ClusterDescription cluster, IEnumerable <ServerDescription> servers) { var list = servers.ToList(); switch (list.Count) { case 0: case 1: return(list); default: { // Follow the "Power of Two Choices" approach // https://web.archive.org/web/20191212194243/https://www.nginx.com/blog/nginx-power-of-two-choices-load-balancing-algorithm/ var index1 = ThreadStaticRandom.Next(list.Count); var index2 = (index1 + 1 + ThreadStaticRandom.Next(list.Count - 1)) % list.Count; var endpoint1 = list[index1].EndPoint; var endpoint2 = list[index2].EndPoint; var server1 = _clusterableServers.First(s => EndPointHelper.Equals(s.Description.EndPoint, endpoint1)); var server2 = _clusterableServers.First(s => EndPointHelper.Equals(s.Description.EndPoint, endpoint2)); var selectedServer = server1.OutstandingOperationsCount < server2.OutstandingOperationsCount ? server1 : server2; return(new[] { selectedServer.Description }); } } }
protected override bool TryGetServer(EndPoint endPoint, out IClusterableServer server) { lock (_serversLock) { server = _servers.FirstOrDefault(s => EndPointHelper.Equals(s.EndPoint, endPoint)); return(server != null); } }
// constructors /// <summary> /// Initializes a new instance of the <see cref="ServerDescription" /> class. /// </summary> /// <param name="serverId">The server identifier.</param> /// <param name="endPoint">The end point.</param> /// <param name="reasonChanged">The reason the server description was last changed.</param> /// <param name="averageRoundTripTime">The average round trip time.</param> /// <param name="canonicalEndPoint">The canonical end point.</param> /// <param name="electionId">The election identifier.</param> /// <param name="heartbeatException">The heartbeat exception.</param> /// <param name="heartbeatInterval">The heartbeat interval.</param> /// <param name="helloOk">Whether the server supports the hello command.</param> /// <param name="lastHeartbeatTimestamp">The last heartbeat timestamp.</param> /// <param name="lastUpdateTimestamp">The last update timestamp.</param> /// <param name="lastWriteTimestamp">The last write timestamp.</param> /// <param name="logicalSessionTimeout">The logical session timeout.</param> /// <param name="maxBatchCount">The maximum batch count.</param> /// <param name="maxDocumentSize">The maximum size of a document.</param> /// <param name="maxMessageSize">The maximum size of a message.</param> /// <param name="maxWireDocumentSize">The maximum size of a wire document.</param> /// <param name="replicaSetConfig">The replica set configuration.</param> /// <param name="state">The server state.</param> /// <param name="tags">The replica set tags.</param> /// <param name="topologyVersion">The topology version.</param> /// <param name="type">The server type.</param> /// <param name="version">The server version.</param> /// <param name="wireVersionRange">The wire version range.</param> /// <exception cref="ArgumentException">EndPoint and ServerId.EndPoint must match.</exception> public ServerDescription( ServerId serverId, EndPoint endPoint, Optional <string> reasonChanged = default(Optional <string>), Optional <TimeSpan> averageRoundTripTime = default(Optional <TimeSpan>), Optional <EndPoint> canonicalEndPoint = default(Optional <EndPoint>), Optional <ElectionId> electionId = default(Optional <ElectionId>), Optional <Exception> heartbeatException = default(Optional <Exception>), Optional <TimeSpan> heartbeatInterval = default(Optional <TimeSpan>), Optional <bool> helloOk = default(Optional <bool>), Optional <DateTime?> lastHeartbeatTimestamp = default(Optional <DateTime?>), Optional <DateTime> lastUpdateTimestamp = default(Optional <DateTime>), Optional <DateTime?> lastWriteTimestamp = default(Optional <DateTime?>), Optional <TimeSpan?> logicalSessionTimeout = default(Optional <TimeSpan?>), Optional <int> maxBatchCount = default(Optional <int>), Optional <int> maxDocumentSize = default(Optional <int>), Optional <int> maxMessageSize = default(Optional <int>), Optional <int> maxWireDocumentSize = default(Optional <int>), Optional <ReplicaSetConfig> replicaSetConfig = default(Optional <ReplicaSetConfig>), Optional <ServerState> state = default(Optional <ServerState>), Optional <TagSet> tags = default(Optional <TagSet>), Optional <TopologyVersion> topologyVersion = default(Optional <TopologyVersion>), Optional <ServerType> type = default(Optional <ServerType>), Optional <SemanticVersion> version = default(Optional <SemanticVersion>), Optional <Range <int> > wireVersionRange = default(Optional <Range <int> >)) { Ensure.IsNotNull(endPoint, nameof(endPoint)); Ensure.IsNotNull(serverId, nameof(serverId)); if (!EndPointHelper.Equals(endPoint, serverId.EndPoint)) { throw new ArgumentException("EndPoint and ServerId.EndPoint must match."); } _averageRoundTripTime = averageRoundTripTime.WithDefault(TimeSpan.Zero); _canonicalEndPoint = canonicalEndPoint.WithDefault(null); _electionId = electionId.WithDefault(null); _endPoint = endPoint; _heartbeatException = heartbeatException.WithDefault(null); _heartbeatInterval = heartbeatInterval.WithDefault(TimeSpan.Zero); _helloOk = helloOk.WithDefault(false); _lastHeartbeatTimestamp = lastHeartbeatTimestamp.WithDefault(null); _lastUpdateTimestamp = lastUpdateTimestamp.WithDefault(DateTime.UtcNow); _lastWriteTimestamp = lastWriteTimestamp.WithDefault(null); _logicalSessionTimeout = logicalSessionTimeout.WithDefault(null); _maxBatchCount = maxBatchCount.WithDefault(1000); _maxDocumentSize = maxDocumentSize.WithDefault(4 * 1024 * 1024); _maxMessageSize = maxMessageSize.WithDefault(Math.Max(_maxDocumentSize + 1024, 16000000)); _maxWireDocumentSize = maxWireDocumentSize.WithDefault(_maxDocumentSize + 16 * 1024); _reasonChanged = reasonChanged.WithDefault("NotSpecified"); _replicaSetConfig = replicaSetConfig.WithDefault(null); _serverId = serverId; _state = state.WithDefault(ServerState.Disconnected); _tags = tags.WithDefault(null); _topologyVersion = topologyVersion.WithDefault(null); _type = type.WithDefault(ServerType.Unknown); _version = version.WithDefault(null); _wireVersionRange = wireVersionRange.WithDefault(null); }
// methods /// <inheritdoc/> public bool Equals(ServerId other) { if (other == null) { return(false); } return (_clusterId.Equals(other._clusterId) && EndPointHelper.Equals(_endPoint, other._endPoint)); }
private void AssertServers(List <ServerDescription> actual, List <ServerDescription> expected) { if (expected.Count == 0) { actual.Count.Should().Be(0); } else { actual.Should().OnlyContain(x => expected.Any(y => EndPointHelper.Equals(x.EndPoint, y.EndPoint))); } }
private ClusterDescription ProcessReplicaSetChange(ClusterDescription clusterDescription, ServerDescriptionChangedEventArgs args) { if (!args.NewServerDescription.Type.IsReplicaSetMember()) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server is a {0}, not a replica set member.", args.NewServerDescription.Type))); } if (args.NewServerDescription.Type == ServerType.ReplicaSetGhost) { return(clusterDescription.WithServerDescription(args.NewServerDescription)); } if (_replicaSetName == null) { _replicaSetName = args.NewServerDescription.ReplicaSetConfig.Name; } if (_replicaSetName != args.NewServerDescription.ReplicaSetConfig.Name) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server was a member of the '{0}' replica set, but should be '{1}'.", args.NewServerDescription.ReplicaSetConfig.Name, _replicaSetName))); } clusterDescription = clusterDescription.WithServerDescription(args.NewServerDescription); clusterDescription = EnsureServers(clusterDescription, args.NewServerDescription); if (args.NewServerDescription.Type == ServerType.ReplicaSetPrimary && args.OldServerDescription.Type != ServerType.ReplicaSetPrimary) { var currentPrimaryEndPoints = clusterDescription.Servers .Where(x => x.Type == ServerType.ReplicaSetPrimary) .Where(x => !EndPointHelper.Equals(x.EndPoint, args.NewServerDescription.EndPoint)) .Select(x => x.EndPoint) .ToList(); if (currentPrimaryEndPoints.Count > 0) { lock (_serversLock) { var currentPrimaries = _servers.Where(x => EndPointHelper.Contains(currentPrimaryEndPoints, x.EndPoint)); foreach (var currentPrimary in currentPrimaries) { // kick off the server to invalidate itself currentPrimary.Invalidate(); // set it to disconnected in the cluster clusterDescription = clusterDescription.WithServerDescription( new ServerDescription(currentPrimary.ServerId, currentPrimary.EndPoint)); } } } } return(clusterDescription); }
/// <summary> /// Gets the server description. /// </summary> /// <returns>The server description.</returns> public ServerDescription GetServerDescription() { var serverDescription = _cluster.Description.Servers.FirstOrDefault(s => EndPointHelper.Equals(s.EndPoint, _endPoint)); if (serverDescription == null) { throw new InvalidOperationException(string.Format( "Cluster does not contain a server with end point: '{0}'.", _endPoint)); } return(serverDescription); }
protected override bool TryGetServer(EndPoint endPoint, out IClusterableServer server) { if (EndPointHelper.Equals(_server.EndPoint, endPoint)) { server = _server; return(true); } else { server = null; return(false); } }
private void ProcessServerDescriptionChanged(ServerDescriptionChangedEventArgs args) { var currentClusterDescription = Description; var currentServerDescription = args.OldServerDescription; var newServerDescription = args.NewServerDescription; var currentServer = _servers.SingleOrDefault(x => EndPointHelper.Equals(x.EndPoint, newServerDescription.EndPoint)); if (currentServer == null) { return; } ClusterDescription newClusterDescription; if (newServerDescription.State == ServerState.Disconnected) { newClusterDescription = currentClusterDescription.WithServerDescription(args.NewServerDescription); } else if (newServerDescription.Type == ServerType.Standalone) { newClusterDescription = currentClusterDescription.WithoutServerDescription(args.NewServerDescription.EndPoint); } else { if (currentClusterDescription.Type == ClusterType.Unknown) { currentClusterDescription = currentClusterDescription.WithType(args.NewServerDescription.Type.ToClusterType()); } switch (currentClusterDescription.Type) { case ClusterType.ReplicaSet: newClusterDescription = ProcessReplicaSetChange(currentClusterDescription, args); break; case ClusterType.Sharded: newClusterDescription = ProcessShardedChange(currentClusterDescription, args); break; case ClusterType.Standalone: throw new MongoInternalException("MultiServerCluster does not support a standalone state."); default: newClusterDescription = currentClusterDescription.WithServerDescription(newServerDescription); break; } } UpdateClusterDescription(newClusterDescription); }
/// <summary> /// Returns a new ClusterDescription with a ServerDescription removed. /// </summary> /// <param name="endPoint">The end point of the server description to remove.</param> /// <returns>A ClusterDescription.</returns> public ClusterDescription WithoutServerDescription(EndPoint endPoint) { var oldServerDescription = _servers.SingleOrDefault(s => s.EndPoint == endPoint); if (oldServerDescription == null) { return(this); } return(new ClusterDescription( _clusterId, _type, _servers.Where(s => !EndPointHelper.Equals(s.EndPoint, endPoint)))); }
/// <summary> /// Determines whether the specified <see cref="ServerDescription" /> can be considered as equal to decide should we publish sdam events or not. /// </summary> /// <param name="other">The other server description.</param> /// <returns><c>true</c>, if sdam events should be suppressed, otherwise <c>false</c>.</returns> public bool SdamEquals(ServerDescription other) { return (EndPointHelper.Equals(_endPoint, other._endPoint) && _type == other.Type && object.Equals(_wireVersionRange, other._wireVersionRange) && EndPointHelper.Equals(_canonicalEndPoint, other._canonicalEndPoint) && // me EndPointHelper.SequenceEquals(_replicaSetConfig?.Members, other._replicaSetConfig?.Members) && // hosts, passives, arbiters object.Equals(_tags, other._tags) && _replicaSetConfig?.Name == other._replicaSetConfig?.Name && // setName _replicaSetConfig?.Version == other._replicaSetConfig?.Version && // setVersion object.Equals(_electionId, other._electionId) && EndPointHelper.Equals(_replicaSetConfig?.Primary, other._replicaSetConfig?.Primary) && // primary _logicalSessionTimeout == other._logicalSessionTimeout); }
public void Description_should_contain_expected_server_description() { var subject = CreateSubject(); subject.Description.Servers.Should().BeEmpty(); subject.Initialize(); _capturedEvents.Clear(); PublishDescription(_endPoint); var description = subject.Description; description.Servers.Should().ContainSingle(s => EndPointHelper.Equals(s.EndPoint, _endPoint) && s.State == ServerState.Connected); _capturedEvents.Next().Should().BeOfType <ClusterDescriptionChangedEvent>(); _capturedEvents.Any().Should().BeFalse(); }
private void ProcessServerDescriptionChanged(ServerDescriptionChangedEventArgs args) { var newServerDescription = args.NewServerDescription; var newClusterDescription = Description; if (!_servers.Any(x => EndPointHelper.Equals(x.EndPoint, newServerDescription.EndPoint))) { return; } if (newServerDescription.State == ServerState.Disconnected) { newClusterDescription = newClusterDescription.WithServerDescription(newServerDescription); } else { if (IsServerValidForCluster(newClusterDescription.Type, Settings.ConnectionMode, newServerDescription.Type)) { if (newClusterDescription.Type == ClusterType.Unknown) { newClusterDescription = newClusterDescription.WithType(newServerDescription.Type.ToClusterType()); } switch (newClusterDescription.Type) { case ClusterType.ReplicaSet: newClusterDescription = ProcessReplicaSetChange(newClusterDescription, args); break; case ClusterType.Sharded: newClusterDescription = ProcessShardedChange(newClusterDescription, args); break; default: throw new MongoInternalException("Unexpected cluster type."); } } else { newClusterDescription = newClusterDescription.WithoutServerDescription(newServerDescription.EndPoint); } } UpdateClusterDescription(newClusterDescription); }
/// <summary> /// Returns a new ClusterDescription with a ServerDescription removed. /// </summary> /// <param name="endPoint">The end point of the server description to remove.</param> /// <returns>A ClusterDescription.</returns> public ClusterDescription WithoutServerDescription(EndPoint endPoint) { var oldServerDescription = _servers.SingleOrDefault(s => s.EndPoint == endPoint); if (oldServerDescription == null) { return(this); } return(new ClusterDescription( _clusterId, _connectionMode, _connectionModeSwitch, _directConnection, _dnsMonitorException, _type, _servers.Where(s => !EndPointHelper.Equals(s.EndPoint, endPoint)))); }
// constructors /// <summary> /// Initializes a new instance of the <see cref="ServerDescription" /> class. /// </summary> /// <param name="serverId">The server identifier.</param> /// <param name="endPoint">The end point.</param> /// <param name="averageRoundTripTime">The average round trip time.</param> /// <param name="canonicalEndPoint">The canonical end point.</param> /// <param name="electionId">The election identifier.</param> /// <param name="heartbeatException">The heartbeat exception.</param> /// <param name="maxBatchCount">The maximum batch count.</param> /// <param name="maxDocumentSize">The maximum size of a document.</param> /// <param name="maxMessageSize">The maximum size of a message.</param> /// <param name="maxWireDocumentSize">The maximum size of a wire document.</param> /// <param name="replicaSetConfig">The replica set configuration.</param> /// <param name="state">The server state.</param> /// <param name="tags">The replica set tags.</param> /// <param name="type">The server type.</param> /// <param name="version">The server version.</param> /// <param name="wireVersionRange">The wire version range.</param> /// <exception cref="System.ArgumentException">EndPoint and ServerId.EndPoint must match.</exception> public ServerDescription( ServerId serverId, EndPoint endPoint, Optional <TimeSpan> averageRoundTripTime = default(Optional <TimeSpan>), Optional <EndPoint> canonicalEndPoint = default(Optional <EndPoint>), Optional <ElectionId> electionId = default(Optional <ElectionId>), Optional <Exception> heartbeatException = default(Optional <Exception>), Optional <int> maxBatchCount = default(Optional <int>), Optional <int> maxDocumentSize = default(Optional <int>), Optional <int> maxMessageSize = default(Optional <int>), Optional <int> maxWireDocumentSize = default(Optional <int>), Optional <ReplicaSetConfig> replicaSetConfig = default(Optional <ReplicaSetConfig>), Optional <ServerState> state = default(Optional <ServerState>), Optional <TagSet> tags = default(Optional <TagSet>), Optional <ServerType> type = default(Optional <ServerType>), Optional <SemanticVersion> version = default(Optional <SemanticVersion>), Optional <Range <int> > wireVersionRange = default(Optional <Range <int> >)) { Ensure.IsNotNull(endPoint, "endPoint"); Ensure.IsNotNull(serverId, "serverId"); if (!EndPointHelper.Equals(endPoint, serverId.EndPoint)) { throw new ArgumentException("EndPoint and ServerId.EndPoint must match."); } _averageRoundTripTime = averageRoundTripTime.WithDefault(TimeSpan.Zero); _canonicalEndPoint = canonicalEndPoint.WithDefault(null); _electionId = electionId.WithDefault(null); _endPoint = endPoint; _heartbeatException = heartbeatException.WithDefault(null); _maxBatchCount = maxBatchCount.WithDefault(1000); _maxDocumentSize = maxDocumentSize.WithDefault(4 * 1024 * 1024); _maxMessageSize = maxMessageSize.WithDefault(Math.Max(_maxDocumentSize + 1024, 16000000)); _maxWireDocumentSize = maxWireDocumentSize.WithDefault(_maxDocumentSize + 16 * 1024); _replicaSetConfig = replicaSetConfig.WithDefault(null); _serverId = serverId; _state = state.WithDefault(ServerState.Disconnected); _tags = tags.WithDefault(null); _type = type.WithDefault(ServerType.Unknown); _version = version.WithDefault(null); _wireVersionRange = wireVersionRange.WithDefault(null); }
private void VerifyOutcome(BsonDocument outcome) { var description = _cluster.Description; var expectedServers = outcome["servers"].AsBsonDocument.Elements.Select(x => new { EndPoint = EndPointHelper.Parse(x.Name), Description = (BsonDocument)x.Value }); var actualServers = description.Servers.Select(x => x.EndPoint); actualServers.Should().BeEquivalentTo(expectedServers.Select(x => x.EndPoint)); foreach (var actualServer in description.Servers) { var expectedServer = expectedServers.Single(x => EndPointHelper.Equals(x.EndPoint, actualServer.EndPoint)); VerifyServer(actualServer, expectedServer.Description); } }
private IDisposable RequestStart(IServerSelector serverSelector, ReadPreference readPreference) { var request = __threadStaticRequest; if (request != null) { var selected = serverSelector.SelectServers(_cluster.Description, new[] { request.ServerDescription }).ToList(); if (selected.Count == 0) { throw new InvalidOperationException("A nested call to RequestStart was made that is not compatible with the existing request."); } request.NestingLevel++; return(new RequestStartResult(this)); } IReadBindingHandle channelBinding; ConnectionId connectionId; var server = _cluster.SelectServer(serverSelector, CancellationToken.None); using (var channel = server.GetChannel(CancellationToken.None)) { if (readPreference.ReadPreferenceMode == ReadPreferenceMode.Primary) { channelBinding = new ReadWriteBindingHandle(new ChannelReadWriteBinding(server, channel.Fork(), NoCoreSession.NewHandle())); } else { channelBinding = new ReadBindingHandle(new ChannelReadBinding(server, channel.Fork(), readPreference, NoCoreSession.NewHandle())); } connectionId = channel.ConnectionDescription.ConnectionId; } var serverDescription = server.Description; var serverInstance = _serverInstances.Single(i => EndPointHelper.Equals(i.EndPoint, serverDescription.EndPoint)); var session = _operationExecutor.StartImplicitSession(CancellationToken.None); __threadStaticRequest = new Request(serverDescription, serverInstance, channelBinding, connectionId, session); return(new RequestStartResult(this)); }
private ClusterDescription EnsureServer(ClusterDescription clusterDescription, EndPoint endPoint, List <IClusterableServer> newServers) { if (_state.Value == State.Disposed) { return(clusterDescription); } IClusterableServer server; Stopwatch stopwatch = new Stopwatch(); lock (_serversLock) { if (_servers.Any(n => EndPointHelper.Equals(n.EndPoint, endPoint))) { return(clusterDescription); } if (_addingServerEventHandler != null) { _addingServerEventHandler(new ClusterAddingServerEvent(ClusterId, endPoint)); } stopwatch.Start(); server = CreateServer(endPoint); server.DescriptionChanged += ServerDescriptionChangedHandler; _servers.Add(server); newServers.Add(server); } clusterDescription = clusterDescription.WithServerDescription(server.Description); stopwatch.Stop(); if (_addedServerEventHandler != null) { _addedServerEventHandler(new ClusterAddedServerEvent(server.ServerId, stopwatch.Elapsed)); } return(clusterDescription); }
private ClusterDescription ProcessStandaloneChange(ClusterDescription clusterDescription, ServerDescriptionChangedEventArgs args) { if (args.NewServerDescription.Type != ServerType.Unknown) { if (args.NewServerDescription.Type == ServerType.Standalone) { foreach (var endPoint in clusterDescription.Servers.Select(s => s.EndPoint).ToList()) { if (!EndPointHelper.Equals(endPoint, args.NewServerDescription.EndPoint)) { clusterDescription = RemoveServer(clusterDescription, endPoint, "Removing all other end points once a standalone is discovered."); } } } else { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, "Server is not a standalone server.")); } } return(clusterDescription.WithServerDescription(args.NewServerDescription)); }
/// <inheritdoc/> public bool Equals(ServerDescription rhs) { if (object.ReferenceEquals(rhs, null) || rhs.GetType() != typeof(ServerDescription)) { return(false); } return (_averageRoundTripTime == rhs._averageRoundTripTime && EndPointHelper.Equals(_endPoint, rhs._endPoint) && object.Equals(_heartbeatException, rhs._heartbeatException) && _maxBatchCount == rhs._maxBatchCount && _maxDocumentSize == rhs._maxDocumentSize && _maxMessageSize == rhs._maxMessageSize && _maxWireDocumentSize == rhs._maxWireDocumentSize && object.Equals(_replicaSetConfig, rhs._replicaSetConfig) && _serverId.Equals(rhs._serverId) && _state == rhs._state && object.Equals(_tags, rhs._tags) && _type == rhs._type && object.Equals(_version, rhs._version) && object.Equals(_wireVersionRange, rhs._wireVersionRange)); }
public IServer SelectServer() { lock (_cluster._descriptionLock) { _descriptionChangedTask = _cluster._descriptionChangedTaskCompletionSource.Task; _description = _cluster._description; } if (!_serverSelectionWaitQueueEntered) { var selectingServerEventHandler = _cluster._selectingServerEventHandler; if (selectingServerEventHandler != null) { // this is our first time through... selectingServerEventHandler(new ClusterSelectingServerEvent( _description, _selector, EventContext.OperationId)); } } MongoIncompatibleDriverException.ThrowIfNotSupported(_description); _connectedServers.Clear(); _connectedServerDescriptions.Clear(); foreach (var description in _description.Servers) { if (description.State == ServerState.Connected && _cluster.TryGetServer(description.EndPoint, out var server)) { _connectedServers.Add(server); _connectedServerDescriptions.Add(description); } } var selectedServersDescriptions = _selector .SelectServers(_description, _connectedServerDescriptions) .ToList(); IServer selectedServer = null; if (selectedServersDescriptions.Count > 0) { var selectedServerDescription = selectedServersDescriptions.Count == 1 ? selectedServersDescriptions[0] : __randomServerSelector.SelectServers(_description, selectedServersDescriptions).Single(); selectedServer = _connectedServers.FirstOrDefault(s => EndPointHelper.Equals(s.EndPoint, selectedServerDescription.EndPoint)); } if (selectedServer != null) { _stopwatch.Stop(); _cluster._selectedServerEventHandler?.Invoke(new ClusterSelectedServerEvent( _description, _selector, selectedServer.Description, _stopwatch.Elapsed, EventContext.OperationId)); } return(selectedServer); }
private ClusterDescription ProcessReplicaSetChange(ClusterDescription clusterDescription, ServerDescriptionChangedEventArgs args) { if (!args.NewServerDescription.Type.IsReplicaSetMember()) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server is a {0}, not a replica set member.", args.NewServerDescription.Type))); } if (args.NewServerDescription.Type == ServerType.ReplicaSetGhost) { return(clusterDescription.WithServerDescription(args.NewServerDescription)); } if (_replicaSetName == null) { _replicaSetName = args.NewServerDescription.ReplicaSetConfig.Name; } if (_replicaSetName != args.NewServerDescription.ReplicaSetConfig.Name) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server was a member of the '{0}' replica set, but should be '{1}'.", args.NewServerDescription.ReplicaSetConfig.Name, _replicaSetName))); } clusterDescription = clusterDescription.WithServerDescription(args.NewServerDescription); clusterDescription = EnsureServers(clusterDescription, args.NewServerDescription); if (args.NewServerDescription.CanonicalEndPoint != null && !EndPointHelper.Equals(args.NewServerDescription.CanonicalEndPoint, args.NewServerDescription.EndPoint)) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, "CanonicalEndPoint is different than seed list EndPoint.")); } if (args.NewServerDescription.Type == ServerType.ReplicaSetPrimary) { if (args.NewServerDescription.ElectionId != null) { if (_maxElectionId != null && _maxElectionId.CompareTo(args.NewServerDescription.ElectionId) > 0) { // ignore this change because we've already seen this election id lock (_serversLock) { var server = _servers.SingleOrDefault(x => EndPointHelper.Equals(args.NewServerDescription.EndPoint, x.EndPoint)); server.Invalidate(); return(clusterDescription.WithServerDescription( new ServerDescription(server.ServerId, server.EndPoint))); } } _maxElectionId = args.NewServerDescription.ElectionId; } var currentPrimaryEndPoints = clusterDescription.Servers .Where(x => x.Type == ServerType.ReplicaSetPrimary) .Where(x => !EndPointHelper.Equals(x.EndPoint, args.NewServerDescription.EndPoint)) .Select(x => x.EndPoint) .ToList(); if (currentPrimaryEndPoints.Count > 0) { lock (_serversLock) { var currentPrimaries = _servers.Where(x => EndPointHelper.Contains(currentPrimaryEndPoints, x.EndPoint)); foreach (var currentPrimary in currentPrimaries) { // kick off the server to invalidate itself currentPrimary.Invalidate(); // set it to disconnected in the cluster clusterDescription = clusterDescription.WithServerDescription( new ServerDescription(currentPrimary.ServerId, currentPrimary.EndPoint)); } } } } return(clusterDescription); }
private ClusterDescription ProcessReplicaSetChange(ClusterDescription clusterDescription, ServerDescriptionChangedEventArgs args, List <IClusterableServer> newServers) { if (!args.NewServerDescription.Type.IsReplicaSetMember()) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server is a {0}, not a replica set member.", args.NewServerDescription.Type))); } if (args.NewServerDescription.Type == ServerType.ReplicaSetGhost) { return(clusterDescription.WithServerDescription(args.NewServerDescription)); } if (_replicaSetName == null) { _replicaSetName = args.NewServerDescription.ReplicaSetConfig.Name; } if (_replicaSetName != args.NewServerDescription.ReplicaSetConfig.Name) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server was a member of the '{0}' replica set, but should be '{1}'.", args.NewServerDescription.ReplicaSetConfig.Name, _replicaSetName))); } clusterDescription = clusterDescription.WithServerDescription(args.NewServerDescription); clusterDescription = EnsureServers(clusterDescription, args.NewServerDescription, newServers); if (args.NewServerDescription.CanonicalEndPoint != null && !EndPointHelper.Equals(args.NewServerDescription.CanonicalEndPoint, args.NewServerDescription.EndPoint)) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, "CanonicalEndPoint is different than seed list EndPoint.")); } if (args.NewServerDescription.Type == ServerType.ReplicaSetPrimary) { if (args.NewServerDescription.ReplicaSetConfig.Version != null) { bool isCurrentPrimaryStale = true; if (_maxElectionInfo != null) { isCurrentPrimaryStale = _maxElectionInfo.IsStale(args.NewServerDescription.ReplicaSetConfig.Version.Value, args.NewServerDescription.ElectionId); var isReportedPrimaryStale = !isCurrentPrimaryStale; if (isReportedPrimaryStale && args.NewServerDescription.ElectionId != null) { // we only invalidate the "newly" reported stale primary if electionId was used. lock (_serversLock) { var server = _servers.SingleOrDefault(x => EndPointHelper.Equals(args.NewServerDescription.EndPoint, x.EndPoint)); server.Invalidate(); return(clusterDescription.WithServerDescription( new ServerDescription(server.ServerId, server.EndPoint))); } } } if (isCurrentPrimaryStale) { _maxElectionInfo = new ElectionInfo( args.NewServerDescription.ReplicaSetConfig.Version.Value, args.NewServerDescription.ElectionId); } } var currentPrimaryEndPoints = clusterDescription.Servers .Where(x => x.Type == ServerType.ReplicaSetPrimary) .Where(x => !EndPointHelper.Equals(x.EndPoint, args.NewServerDescription.EndPoint)) .Select(x => x.EndPoint) .ToList(); if (currentPrimaryEndPoints.Count > 0) { lock (_serversLock) { var currentPrimaries = _servers.Where(x => EndPointHelper.Contains(currentPrimaryEndPoints, x.EndPoint)); foreach (var currentPrimary in currentPrimaries) { // kick off the server to invalidate itself currentPrimary.Invalidate(); // set it to disconnected in the cluster clusterDescription = clusterDescription.WithServerDescription( new ServerDescription(currentPrimary.ServerId, currentPrimary.EndPoint)); } } } } return(clusterDescription); }
private ClusterDescription ProcessReplicaSetChange(ClusterDescription clusterDescription, ServerDescriptionChangedEventArgs args, List <IClusterableServer> newServers) { if (!args.NewServerDescription.Type.IsReplicaSetMember()) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server is a {0}, not a replica set member.", args.NewServerDescription.Type))); } if (args.NewServerDescription.Type == ServerType.ReplicaSetGhost) { return(clusterDescription.WithServerDescription(args.NewServerDescription)); } if (_replicaSetName == null) { _replicaSetName = args.NewServerDescription.ReplicaSetConfig.Name; } if (_replicaSetName != args.NewServerDescription.ReplicaSetConfig.Name) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, string.Format("Server was a member of the '{0}' replica set, but should be '{1}'.", args.NewServerDescription.ReplicaSetConfig.Name, _replicaSetName))); } clusterDescription = clusterDescription.WithServerDescription(args.NewServerDescription); clusterDescription = EnsureServers(clusterDescription, args.NewServerDescription, newServers); if (args.NewServerDescription.CanonicalEndPoint != null && !EndPointHelper.Equals(args.NewServerDescription.CanonicalEndPoint, args.NewServerDescription.EndPoint)) { return(RemoveServer(clusterDescription, args.NewServerDescription.EndPoint, "CanonicalEndPoint is different than seed list EndPoint.")); } if (args.NewServerDescription.Type == ServerType.ReplicaSetPrimary) { if (args.NewServerDescription.ReplicaSetConfig.Version != null) { bool isCurrentPrimaryStale = true; if (_maxElectionInfo != null) { isCurrentPrimaryStale = _maxElectionInfo.IsStale(args.NewServerDescription.ReplicaSetConfig.Version.Value, args.NewServerDescription.ElectionId); var isReportedPrimaryStale = _maxElectionInfo.IsFresher( args.NewServerDescription.ReplicaSetConfig.Version.Value, args.NewServerDescription.ElectionId); if (isReportedPrimaryStale && args.NewServerDescription.ElectionId != null) { // we only invalidate the "newly" reported stale primary if electionId was used. lock (_serversLock) { var server = _servers.SingleOrDefault(x => EndPointHelper.Equals(args.NewServerDescription.EndPoint, x.EndPoint)); server.Invalidate(); _sdamInformationEventHandler?.Invoke(new SdamInformationEvent(() => string.Format( @"Invalidating server: Setting ServerType to ""Unknown"" for {0} because it " + @"claimed to be the replica set primary for replica set ""{1}"" but sent a " + @"(setVersion, electionId) tuple of ({2}, {3}) that was less than than the " + @"largest tuple seen, (maxSetVersion, maxElectionId), of ({4}, {5}).", args.NewServerDescription.EndPoint, args.NewServerDescription.ReplicaSetConfig.Name, args.NewServerDescription.ReplicaSetConfig.Version, args.NewServerDescription.ElectionId, _maxElectionInfo.SetVersion, _maxElectionInfo.ElectionId))); return(clusterDescription.WithServerDescription( new ServerDescription(server.ServerId, server.EndPoint))); } } } if (isCurrentPrimaryStale) { if (_maxElectionInfo == null) { _sdamInformationEventHandler?.Invoke(new SdamInformationEvent(() => string.Format( @"Initializing (maxSetVersion, maxElectionId): Saving tuple " + @"(setVersion, electionId) of ({0}, {1}) as (maxSetVersion, maxElectionId) for " + @"replica set ""{2}"" because replica set primary {3} sent ({0}, {1}), the first " + @"(setVersion, electionId) tuple ever seen for replica set ""{4}"".", args.NewServerDescription.ReplicaSetConfig.Version, args.NewServerDescription.ElectionId, args.NewServerDescription.ReplicaSetConfig.Name, args.NewServerDescription.EndPoint, args.NewServerDescription.ReplicaSetConfig.Name))); } else { if (_maxElectionInfo.SetVersion < args.NewServerDescription.ReplicaSetConfig.Version.Value) { _sdamInformationEventHandler?.Invoke(new SdamInformationEvent(() => string.Format( @"Updating stale setVersion: Updating the current " + @"(maxSetVersion, maxElectionId) tuple from ({0}, {1}) to ({2}, {3}) for " + @"replica set ""{4}"" because replica set primary {5} sent ({6}, {7})—a larger " + @"(setVersion, electionId) tuple then the saved tuple, ({0}, {1}).", _maxElectionInfo.SetVersion, _maxElectionInfo.ElectionId, args.NewServerDescription.ReplicaSetConfig.Version, args.NewServerDescription.ElectionId, args.NewServerDescription.ReplicaSetConfig.Name, args.NewServerDescription.EndPoint, args.NewServerDescription.ReplicaSetConfig.Version, args.NewServerDescription.ElectionId))); } else // current primary is stale & setVersion is not stale ⇒ the electionId must be stale { _sdamInformationEventHandler?.Invoke(new SdamInformationEvent(() => string.Format( @"Updating stale electionId: Updating the current " + @"(maxSetVersion, maxElectionId) tuple from ({0}, {1}) to ({2}, {3}) for " + @"replica set ""{4}"" because replica set primary {5} sent ({6}, {7})—" + @"a larger (setVersion, electionId) tuple than the saved tuple, ({0}, {1}).", _maxElectionInfo.SetVersion, _maxElectionInfo.ElectionId, args.NewServerDescription.ReplicaSetConfig.Version, args.NewServerDescription.ElectionId, args.NewServerDescription.ReplicaSetConfig.Name, args.NewServerDescription.EndPoint, args.NewServerDescription.ReplicaSetConfig.Version, args.NewServerDescription.ElectionId))); } } _maxElectionInfo = new ElectionInfo( args.NewServerDescription.ReplicaSetConfig.Version.Value, args.NewServerDescription.ElectionId); } } var currentPrimaryEndPoints = clusterDescription.Servers .Where(x => x.Type == ServerType.ReplicaSetPrimary) .Where(x => !EndPointHelper.Equals(x.EndPoint, args.NewServerDescription.EndPoint)) .Select(x => x.EndPoint) .ToList(); if (currentPrimaryEndPoints.Count > 0) { lock (_serversLock) { var currentPrimaries = _servers.Where(x => EndPointHelper.Contains(currentPrimaryEndPoints, x.EndPoint)); foreach (var currentPrimary in currentPrimaries) { // kick off the server to invalidate itself currentPrimary.Invalidate(); // set it to disconnected in the cluster clusterDescription = clusterDescription.WithServerDescription( new ServerDescription(currentPrimary.ServerId, currentPrimary.EndPoint)); } } } } return(clusterDescription); }