// constructors /// <summary> /// Initializes a new instance of the <see cref="MongoServerInstance"/> class. /// </summary> /// <param name="settings">The settings.</param> /// <param name="address">The address.</param> internal MongoServerInstance(MongoServerSettings settings, MongoServerAddress address) { _settings = settings; _address = address; _sequentialId = Interlocked.Increment(ref __nextSequentialId); _state = MongoServerState.Disconnected; _serverInfo = new ServerInformation { MaxDocumentSize = MongoDefaults.MaxDocumentSize, MaxMessageLength = MongoDefaults.MaxMessageLength, InstanceType = MongoServerInstanceType.Unknown }; _connectionPool = new MongoConnectionPool(this); _pingTimeAggregator = new PingTimeAggregator(5); _permanentlyDisconnected = false; // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address); _stateVerificationAcquireConnectionOptions = new MongoConnectionPool.AcquireConnectionOptions { OkToAvoidWaitingByCreatingNewConnection = false, OkToExceedMaxConnectionPoolSize = true, OkToExceedWaitQueueSize = true, WaitQueueTimeout = TimeSpan.FromSeconds(2) }; }
/// <summary> /// Initializes a new instance of the <see cref="ShardedMongoServerProxy"/> class. /// </summary> /// <param name="server">The server.</param> /// <param name="instances">The instances.</param> /// <param name="connectionQueue">The state change queue.</param> /// <param name="connectionAttempt">The connection attempt.</param> /// <remarks>This constructor is used when the instances have already been instructed to connect.</remarks> protected MultipleInstanceMongoServerProxy(MongoServer server, IEnumerable<MongoServerInstance> instances, BlockingQueue<MongoServerInstance> connectionQueue, int connectionAttempt) { _state = MongoServerState.Connecting; _server = server; _connectedInstances = new ConnectedInstanceCollection(); _connectionAttempt = connectionAttempt; _outstandingInstanceConnections = connectionQueue.Count; ThreadPool.QueueUserWorkItem(_ => { while (connectionQueue.Count > 0) { var instance = connectionQueue.Dequeue(); Interlocked.Decrement(ref _outstandingInstanceConnections); } }); // It's important to have our own copy of this list because it might get modified during iteration. _instances = instances.ToList(); foreach (var instance in instances) { instance.StateChanged += InstanceStateChanged; ProcessInstanceStateChange(instance); } }
private void InstanceStateChanged( object sender, object args ) { lock (instances) { if (instances.Any(i => i.State == MongoServerState.Connected && i.IsPrimary)) { // Console.WriteLine("Server state: Connected"); state = MongoServerState.Connected; return; } if (settings.SlaveOk) { if (instances.Any(i => i.State == MongoServerState.Connected && (i.IsSecondary || i.IsPassive))) { // Console.WriteLine("Server state: Connected"); state = MongoServerState.Connected; return; } } if (instances.Any(i => i.State == MongoServerState.Connecting)) { // Console.WriteLine("Server state: Connecting"); state = MongoServerState.Connecting; return; } // Console.WriteLine("Server state: Disconnected"); state = MongoServerState.Disconnected; } }
/// <summary> /// Initializes a new instance of the <see cref="MultipleInstanceMongoServerProxy"/> class. /// </summary> /// <param name="settings">The settings.</param> /// <param name="instances">The instances.</param> /// <param name="connectionQueue">The state change queue.</param> /// <param name="connectionAttempt">The connection attempt.</param> /// <remarks>This constructor is used when the instances have already been instructed to connect.</remarks> protected MultipleInstanceMongoServerProxy(MongoServerSettings settings, IEnumerable <MongoServerInstance> instances, BlockingQueue <MongoServerInstance> connectionQueue, int connectionAttempt) { _state = MongoServerState.Connecting; _settings = settings; _connectedInstances = new ConnectedInstanceCollection(); _connectionAttempt = connectionAttempt; _outstandingInstanceConnections = connectionQueue.Count; ThreadPool.QueueUserWorkItem(_ => { while (connectionQueue.Count > 0) { connectionQueue.Dequeue(); Interlocked.Decrement(ref _outstandingInstanceConnections); } }); // It's important to have our own copy of this list because it might get modified during iteration. _instances = instances.ToList(); foreach (var instance in instances) { instance.StateChanged += InstanceStateChanged; ProcessInstanceStateChange(instance); } }
/// <remarks>This method must be called outside of a lock.</remarks> private void SetState(MongoServerState newState, ServerInformation newServerInfo) { bool raiseChangedEvent = false; lock (_serverInstanceLock) { if (_state != newState) { _state = newState; raiseChangedEvent = true; } if (newState == MongoServerState.Disconnected) { _connectionPool.Clear(); } if (_serverInfo != newServerInfo && _serverInfo.IsDifferentFrom(newServerInfo)) { _serverInfo = newServerInfo; raiseChangedEvent = true; } } if (raiseChangedEvent) { OnStateChanged(); } }
/// <summary> /// Disconnects this instance. /// </summary> internal void Disconnect() { // Console.WriteLine("MongoServerInstance[{0}]: Disconnect called.", sequentialId); lock (_serverInstanceLock) { if (_stateVerificationTimer != null) { _stateVerificationTimer.Dispose(); _stateVerificationTimer = null; } if (_state == MongoServerState.Disconnecting || _state == MongoServerState.Disconnected) { return; } // set the state here because SetState raises an event that should not be raised while holding a lock _state = MongoServerState.Disconnecting; } // we know for certain state has just changed. OnStateChanged(); try { _connectionPool.Clear(); } finally { SetState(MongoServerState.Disconnected); } }
// constructors /// <summary> /// Initializes a new instance of the <see cref="DiscoveringMongoServerProxy"/> class. /// </summary> /// <param name="sequentialId">The sequential id.</param> /// <param name="settings">The settings.</param> public DiscoveringMongoServerProxy(int sequentialId, MongoServerProxySettings settings) { _state = MongoServerState.Disconnected; _sequentialId = sequentialId; _settings = settings; _instances = settings.Servers.Select(a => new MongoServerInstance(settings, a)).ToList().AsReadOnly(); }
/// <summary> /// Determines the state of the server. /// </summary> /// <param name="currentState">State of the current.</param> /// <param name="instances">The instances.</param> /// <returns>The server state.</returns> protected override MongoServerState DetermineServerState(MongoServerState currentState, IEnumerable <MongoServerInstance> instances) { if (!instances.Any()) { return(MongoServerState.Disconnected); } // the order of the tests is significant // and resolves ambiguities when more than one state might match if (currentState == MongoServerState.Disconnected) { return(MongoServerState.Disconnected); } else if (currentState == MongoServerState.Disconnecting) { if (instances.All(i => i.State == MongoServerState.Disconnected)) { return(MongoServerState.Disconnected); } return(MongoServerState.Disconnecting); } else { if (instances.Any(i => i.State == MongoServerState.Connected)) { return(MongoServerState.Connected); } return(MongoServerState.Connecting); } }
/// <summary> /// Disconnects the server. /// </summary> public void Disconnect() { lock (_lock) { if (_state == MongoServerState.Disconnected || _state == MongoServerState.Disconnecting) { return; } _state = MongoServerState.Disconnecting; try { _connectedInstances.Clear(); foreach (var instance in _instances) { try { instance.Disconnect(); } catch { } // ignore disconnection errors } } finally { _state = MongoServerState.Disconnected; } } }
internal void ClearInstances() { lock (instances) { instances.ForEach(i => { i.StateChanged -= InstanceStateChanged; }); instances.Clear(); state = MongoServerState.Disconnected; } }
/// <summary> /// Connects this instance. /// </summary> internal void Connect() { // Console.WriteLine("MongoServerInstance[{0}]: Connect() called.", sequentialId); lock (_serverInstanceLock) { if (_permanentlyDisconnected || _state == MongoServerState.Connecting || _state == MongoServerState.Connected) { return; } _connectException = null; // set the state manually here because SetState raises an event that shouldn't be raised // while holding a lock. _state = MongoServerState.Connecting; } // We know for certain that the state just changed OnStateChanged(); try { var connection = _connectionPool.AcquireConnection(null); try { Ping(connection); LookupServerInformation(connection); } finally { _connectionPool.ReleaseConnection(connection); } SetState(MongoServerState.Connected); } catch (Exception ex) { lock (_serverInstanceLock) { _connectException = ex; } _connectionPool.Clear(); Interlocked.Exchange(ref _connectException, ex); SetState(MongoServerState.Disconnected); throw; } finally { lock (_serverInstanceLock) { if (_stateVerificationTimer == null) { _stateVerificationTimer = new Timer(o => StateVerificationTimerCallback(), null, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10)); } } } }
private MongoServerState state; // always use property to set value so event gets raised #endregion #region constructors internal MongoServerInstance( MongoServer server, MongoServerAddress address ) { this.server = server; this.address = address; this.maxDocumentSize = MongoDefaults.MaxDocumentSize; this.maxMessageLength = MongoDefaults.MaxMessageLength; this.state = MongoServerState.Disconnected; }
internal void Connect( bool slaveOk ) { if (state != MongoServerState.Disconnected) { var message = string.Format("MongoServerInstance.Connect called when state is: {0}", state); throw new InvalidOperationException(message); } State = MongoServerState.Connecting; connectException = null; try { endPoint = address.ToIPEndPoint(server.Settings.AddressFamily); var connectionPool = new MongoConnectionPool(this); try { var connection = connectionPool.AcquireConnection(null); try { try { var isMasterCommand = new CommandDocument("ismaster", 1); isMasterResult = connection.RunCommand("admin.$cmd", QueryFlags.SlaveOk, isMasterCommand); } catch (MongoCommandException ex) { isMasterResult = ex.CommandResult; throw; } isPrimary = isMasterResult.Response["ismaster", false].ToBoolean(); isSecondary = isMasterResult.Response["secondary", false].ToBoolean(); isPassive = isMasterResult.Response["passive", false].ToBoolean(); isArbiter = isMasterResult.Response["arbiterOnly", false].ToBoolean(); if (!isPrimary && !slaveOk) { throw new MongoConnectionException("Server is not a primary and SlaveOk is false"); } maxDocumentSize = isMasterResult.Response["maxBsonObjectSize", MongoDefaults.MaxDocumentSize].ToInt32(); maxMessageLength = Math.Max(MongoDefaults.MaxMessageLength, maxDocumentSize + 1024); // derived from maxDocumentSize } finally { connectionPool.ReleaseConnection(connection); } } catch { connectionPool.Close(); throw; } State = MongoServerState.Connected; this.connectionPool = connectionPool; } catch (Exception ex) { State = MongoServerState.Disconnected; connectException = ex; throw; } }
private MongoServerState _state; // always use property to set value so event gets raised // constructors internal MongoServerInstance(MongoServer server, MongoServerAddress address) { _server = server; _address = address; _sequentialId = Interlocked.Increment(ref __nextSequentialId); _maxDocumentSize = MongoDefaults.MaxDocumentSize; _maxMessageLength = MongoDefaults.MaxMessageLength; _state = MongoServerState.Disconnected; _connectionPool = new MongoConnectionPool(this); // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address); }
internal void SetState(MongoServerState state) { lock (_serverInstanceLock) { if (_state != state) { _state = state; OnStateChanged(); } } }
/// <summary> /// Connects to the server. Normally there is no need to call this method as /// the driver will connect to the server automatically when needed. /// </summary> /// <param name="timeout">How long to wait before timing out.</param> public virtual void Connect( TimeSpan timeout ) { lock (serverLock) { if (state != MongoServerState.Connected) { state = MongoServerState.Connecting; try { switch (settings.ConnectionMode) { case ConnectionMode.Direct: var directConnector = new DirectConnector(this); directConnector.Connect(timeout); primaryConnectionPool = new MongoConnectionPool(this, directConnector.Connection); secondaryConnectionPools = null; replicaSet = null; maxDocumentSize = directConnector.MaxDocumentSize; maxMessageLength = directConnector.MaxMessageLength; break; case ConnectionMode.ReplicaSet: var replicaSetConnector = new ReplicaSetConnector(this); replicaSetConnector.Connect(timeout); primaryConnectionPool = new MongoConnectionPool(this, replicaSetConnector.PrimaryConnection); if (settings.SlaveOk && replicaSetConnector.SecondaryConnections.Count > 0) { secondaryConnectionPools = new List <MongoConnectionPool>(); foreach (var connection in replicaSetConnector.SecondaryConnections) { var secondaryConnectionPool = new MongoConnectionPool(this, connection); secondaryConnectionPools.Add(secondaryConnectionPool); } } else { secondaryConnectionPools = null; } replicaSet = replicaSetConnector.ReplicaSet; maxDocumentSize = replicaSetConnector.MaxDocumentSize; maxMessageLength = replicaSetConnector.MaxMessageLength; break; default: throw new MongoInternalException("Invalid ConnectionMode"); } state = MongoServerState.Connected; } catch { state = MongoServerState.Disconnected; throw; } } } }
// constructors internal MongoServerInstance(MongoServer server, MongoServerAddress address) { this.server = server; this.address = address; this.sequentialId = Interlocked.Increment(ref nextSequentialId); this.maxDocumentSize = MongoDefaults.MaxDocumentSize; this.maxMessageLength = MongoDefaults.MaxMessageLength; this.state = MongoServerState.Disconnected; this.connectionPool = new MongoConnectionPool(this); this.tags = new HashSet<string>(); // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address); }
internal void Disconnect() { if (state != MongoServerState.Disconnected) { try { connectionPool.Close(); connectionPool = null; } finally { State = MongoServerState.Disconnected; } } }
/// <summary> /// Connects to the instances respecting the timeout and readPreference. /// </summary> /// <param name="timeout">The timeout.</param> /// <param name="readPreference">The read preference.</param> public void Connect(TimeSpan timeout, ReadPreference readPreference) { try { EnsureInstanceManager(timeout); } catch { _state = MongoServerState.Disconnected; throw; } _serverProxy.Connect(timeout, readPreference); }
/// <summary> /// Sets the state. /// </summary> /// <param name="state">The state.</param> internal void SetState(MongoServerState state) { lock (_serverInstanceLock) { if (_state == state) { return; } _state = state; } OnStateChanged(); }
internal void SetState(MongoServerState state, bool isPrimary, bool isSecondary, bool isPassive, bool isArbiter) { lock (serverInstanceLock) { if (this.state != state || this.isPrimary != isPrimary || this.isSecondary != isSecondary || this.isPassive != isPassive || this.isArbiter != isArbiter) { this.state = state; this.isPrimary = isPrimary; this.isSecondary = isSecondary; this.isPassive = isPassive; this.isArbiter = isArbiter; OnStateChanged(); } } }
// private methods private void EnsureInstanceManager(TimeSpan timeout) { if (_serverProxy == null) { lock (_lock) { if (_serverProxy == null) { _connectionAttempt++; _state = MongoServerState.Connecting; Discover(timeout); } } } }
internal void Disconnect() { if (state != MongoServerState.Disconnected) { try { // if we fail during Connect the connectionPool field will still be null if (connectionPool != null) { connectionPool.Close(); connectionPool = null; } } finally { State = MongoServerState.Disconnected; } } }
/// <summary> /// Connects to the instances respecting the timeout and readPreference. /// </summary> /// <param name="timeout">The timeout.</param> /// <param name="readPreference">The read preference.</param> public void Connect(TimeSpan timeout, ReadPreference readPreference) { var timeoutAt = DateTime.UtcNow + timeout; while (DateTime.UtcNow < timeoutAt) { if (ChooseServerInstance(_connectedInstances, readPreference) != null) { return; } if (Interlocked.CompareExchange(ref _outstandingInstanceConnections, 0, 0) > 0) { Thread.Sleep(TimeSpan.FromMilliseconds(20)); continue; } lock (_lock) { // test this again (kinda like the double lock check pattern). This value may // be different and we don't want to issue another round of connects needlessly. if (Interlocked.CompareExchange(ref _outstandingInstanceConnections, 0, 0) > 0) { Thread.Sleep(TimeSpan.FromMilliseconds(20)); continue; } // if we are already fully connected and an instance still isn't chosen, // then one simply doesn't exist, so we'll break immediately and throw a // connection exception. if (_state == MongoServerState.Connected) { break; } _state = MongoServerState.Connecting; _connectionAttempt++; foreach (var instance in _instances) { ConnectInstance(instance); } } } ThrowConnectionException(readPreference); }
// constructors /// <summary> /// Initializes a new instance of the <see cref="MongoServerInstance"/> class. /// </summary> /// <param name="server">The server.</param> /// <param name="address">The address.</param> internal MongoServerInstance(MongoServer server, MongoServerAddress address) { _server = server; _address = address; _sequentialId = Interlocked.Increment(ref __nextSequentialId); _state = MongoServerState.Disconnected; _serverInfo = new ServerInformation { MaxDocumentSize = MongoDefaults.MaxDocumentSize, MaxMessageLength = MongoDefaults.MaxMessageLength, InstanceType = MongoServerInstanceType.Unknown }; _connectionPool = new MongoConnectionPool(this); _pingTimeAggregator = new PingTimeAggregator(5); _permanentlyDisconnected = false; // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address); }
// constructors /// <summary> /// Initializes a new instance of the <see cref="MongoServerInstance"/> class. /// </summary> /// <param name="settings">The settings.</param> /// <param name="address">The address.</param> internal MongoServerInstance(MongoServerSettings settings, MongoServerAddress address) { _settings = settings; _address = address; _sequentialId = Interlocked.Increment(ref __nextSequentialId); _state = MongoServerState.Disconnected; _serverInfo = new ServerInformation { MaxDocumentSize = MongoDefaults.MaxDocumentSize, MaxMessageLength = MongoDefaults.MaxMessageLength, InstanceType = MongoServerInstanceType.Unknown }; _connectionPool = new MongoConnectionPool(this); _pingTimeAggregator = new PingTimeAggregator(5); _permanentlyDisconnected = false; // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address); }
private void ProcessInstanceStateChange(MongoServerInstance instance) { lock (_lock) { if (_instances.Contains(instance)) { if (instance.State == MongoServerState.Connected) { if (!IsValidInstance(instance)) { RemoveInstance(instance); return; } var myAddress = instance.IsMasterResult.MyAddress; if (myAddress != null && instance.Address != myAddress) { if (!_instances.Any(x => x.Address == myAddress)) { instance.Address = myAddress; } else { // we need to get rid of the duplicate. RemoveInstance(instance); return; } } if (_state != MongoServerState.Disconnecting && _state != MongoServerState.Disconnected) { _connectedInstances.EnsureContains(instance); ProcessConnectedInstanceStateChange(instance); } } else { _connectedInstances.Remove(instance); ProcessDisconnectedInstanceStateChange(instance); } } _state = DetermineServerState(_state, _instances); } }
/// <summary> /// Determines the state of the server. /// </summary> /// <param name="currentState">State of the current.</param> /// <param name="instances">The instances.</param> /// <returns>The server state.</returns> protected override MongoServerState DetermineServerState(MongoServerState currentState, IEnumerable <MongoServerInstance> instances) { if (!instances.Any()) { return(MongoServerState.Disconnected); } // the order of the tests is significant // and resolves ambiguities when more than one state might match if (currentState == MongoServerState.Disconnecting) { if (instances.All(i => i.State == MongoServerState.Disconnected)) { return(MongoServerState.Disconnected); } } else { if (instances.All(i => i.State == MongoServerState.Disconnected)) { return(MongoServerState.Disconnected); } else if (instances.All(i => i.State == MongoServerState.Connected)) { return(MongoServerState.Connected); } else if (instances.Any(i => i.State == MongoServerState.Connecting)) { return(MongoServerState.Connecting); } else if (instances.Any(i => i.State == MongoServerState.Unknown)) { return(MongoServerState.Unknown); } else if (instances.Any(i => i.State == MongoServerState.Connected)) { return(MongoServerState.ConnectedToSubset); } throw new MongoInternalException("Unexpected server instance states."); } return(currentState); }
/// <summary> /// Determines the state of the server. /// </summary> /// <param name="currentState">State of the current.</param> /// <param name="instances">The instances.</param> /// <returns>The server state.</returns> protected override MongoServerState DetermineServerState(MongoServerState currentState, IEnumerable<MongoServerInstance> instances) { if (!instances.Any()) { return MongoServerState.Disconnected; } // the order of the tests is significant // and resolves ambiguities when more than one state might match if (currentState == MongoServerState.Disconnecting) { if (instances.All(i => i.State == MongoServerState.Disconnected)) { return MongoServerState.Disconnected; } } else { if (instances.All(i => i.State == MongoServerState.Disconnected)) { return MongoServerState.Disconnected; } else if (instances.All(i => i.State == MongoServerState.Connected)) { return MongoServerState.Connected; } else if (instances.Any(i => i.State == MongoServerState.Connecting)) { return MongoServerState.Connecting; } else if (instances.Any(i => i.State == MongoServerState.Unknown)) { return MongoServerState.Unknown; } else if (instances.Any(i => i.State == MongoServerState.Connected)) { return MongoServerState.ConnectedToSubset; } throw new MongoInternalException("Unexpected server instance states."); } return currentState; }
/// <summary> /// Disconnects from the server. Normally there is no need to call this method so /// you should be sure to have a good reason to call it. /// </summary> public virtual void Disconnect() { // normally called from a connection when there is a SocketException // but anyone can call it if they want to close all sockets to the server lock (serverLock) { if (state == MongoServerState.Connected) { primaryConnectionPool.Close(); primaryConnectionPool = null; if (secondaryConnectionPools != null) { foreach (var secondaryConnectionPool in secondaryConnectionPools) { secondaryConnectionPool.Close(); } secondaryConnectionPools = null; } state = MongoServerState.Disconnected; } } }
/// <summary> /// Ensures that an instance with the address exists. /// </summary> /// <param name="address">The address.</param> protected void EnsureInstanceWithAddress(MongoServerAddress address) { if (address == null) { throw new ArgumentNullException("address"); } lock (_lock) { if (!_instances.Any(x => x.Address == address)) { var instance = new MongoServerInstance(_server, address); AddInstance(instance); if (_state != MongoServerState.Disconnecting && _state != MongoServerState.Disconnected) { _state = MongoServerState.Connecting; ConnectInstance(instance); } } } }
internal void Connect( bool slaveOk ) { if (state != MongoServerState.Disconnected) { var message = string.Format("MongoServerInstance.Connect can only be called when state is Disconnected, not when state is {0}.", state); throw new InvalidOperationException(message); } State = MongoServerState.Connecting; connectException = null; try { endPoint = address.ToIPEndPoint(server.Settings.AddressFamily); var connectionPool = new MongoConnectionPool(this); try { var connection = connectionPool.AcquireConnection(null); try { try { var isMasterCommand = new CommandDocument("ismaster", 1); isMasterResult = connection.RunCommand("admin.$cmd", QueryFlags.SlaveOk, isMasterCommand); } catch (MongoCommandException ex) { isMasterResult = ex.CommandResult; throw; } isPrimary = isMasterResult.Response["ismaster", false].ToBoolean(); isSecondary = isMasterResult.Response["secondary", false].ToBoolean(); isPassive = isMasterResult.Response["passive", false].ToBoolean(); isArbiter = isMasterResult.Response["arbiterOnly", false].ToBoolean(); if (!isPrimary && !slaveOk) { throw new MongoConnectionException("Server is not a primary and SlaveOk is false."); } maxDocumentSize = isMasterResult.Response["maxBsonObjectSize", MongoDefaults.MaxDocumentSize].ToInt32(); maxMessageLength = Math.Max(MongoDefaults.MaxMessageLength, maxDocumentSize + 1024); // derived from maxDocumentSize var buildInfoCommand = new CommandDocument("buildinfo", 1); var buildInfoResult = connection.RunCommand("admin.$cmd", QueryFlags.SlaveOk, buildInfoCommand); buildInfo = new MongoServerBuildInfo( buildInfoResult.Response["bits"].ToInt32(), // bits buildInfoResult.Response["gitVersion"].AsString, // gitVersion buildInfoResult.Response["sysInfo"].AsString, // sysInfo buildInfoResult.Response["version"].AsString // versionString ); } finally { connectionPool.ReleaseConnection(connection); } } catch { connectionPool.Close(); throw; } State = MongoServerState.Connected; this.connectionPool = connectionPool; } catch (Exception ex) { State = MongoServerState.Disconnected; connectException = ex; throw; } }
/// <summary> /// Determines the state of the server. /// </summary> /// <param name="currentState">State of the current.</param> /// <param name="instances">The instances.</param> /// <returns>The state of the server.</returns> protected abstract MongoServerState DetermineServerState(MongoServerState currentState, IEnumerable<MongoServerInstance> instances);
/// <summary> /// Determines the state of the server. /// </summary> /// <param name="currentState">State of the current.</param> /// <param name="instances">The instances.</param> /// <returns>The server state.</returns> protected override MongoServerState DetermineServerState(MongoServerState currentState, IEnumerable<MongoServerInstance> instances) { if (!instances.Any()) { return MongoServerState.Disconnected; } // the order of the tests is significant // and resolves ambiguities when more than one state might match if (currentState == MongoServerState.Disconnected) { return MongoServerState.Disconnected; } else if (currentState == MongoServerState.Disconnecting) { if (instances.All(i => i.State == MongoServerState.Disconnected)) { return MongoServerState.Disconnected; } return MongoServerState.Disconnecting; } else { if (instances.Any(i => i.State == MongoServerState.Connected)) { return MongoServerState.Connected; } return MongoServerState.Connecting; } }
private void ProcessInstanceStateChange(MongoServerInstance instance) { lock (_lock) { if (_instances.Contains(instance)) { if (instance.State == MongoServerState.Connected) { if (!IsValidInstance(instance)) { RemoveInstance(instance); return; } if (instance.Address != instance.IsMasterResult.MyAddress) { if (!_instances.Any(x => x.Address == instance.IsMasterResult.MyAddress)) { instance.Address = instance.IsMasterResult.MyAddress; } else { // we need to get rid of the duplicate. RemoveInstance(instance); return; } } if (_state != MongoServerState.Disconnecting && _state != MongoServerState.Disconnected) { _connectedInstances.EnsureContains(instance); ProcessConnectedInstanceStateChange(instance); } } else { _connectedInstances.Remove(instance); } } _state = DetermineServerState(_state, _instances); } }
private void SetState(MongoServerState state, ServerInformation serverInfo) { var currentServerInfo = Interlocked.CompareExchange(ref _stateInfo, null, null); bool raiseChangedEvent = false; lock (_stateLock) { if (_state != state) { _state = state; raiseChangedEvent = true; } if (state == MongoServerState.Disconnected) { _connectionPool.Clear(); } if (currentServerInfo != serverInfo && currentServerInfo.IsDifferentFrom(serverInfo)) { Interlocked.Exchange(ref _stateInfo, serverInfo); raiseChangedEvent = true; } } if (raiseChangedEvent) { OnStateChanged(); } }
private void SetState(MongoServerState state) { lock (_lock) { _state = state; } }
internal void SetState( MongoServerState state, bool isPrimary, bool isSecondary, bool isPassive, bool isArbiter) { lock (_serverInstanceLock) { if (_state != state || _isPrimary != isPrimary || _isSecondary != isSecondary || _isPassive != isPassive || _isArbiter != isArbiter) { _state = state; _isPrimary = isPrimary; _isSecondary = isSecondary; _isPassive = isPassive; _isArbiter = isArbiter; OnStateChanged(); } } }
// constructors /// <summary> /// Initializes a new instance of the <see cref="DiscoveringMongoServerProxy"/> class. /// </summary> /// <param name="settings">The settings.</param> public DiscoveringMongoServerProxy(MongoServerSettings settings) { _state = MongoServerState.Disconnected; _settings = settings; _instances = settings.Servers.Select(a => new MongoServerInstance(settings, a)).ToList().AsReadOnly(); }
private void SetState( MongoServerState state, MongoServerInstanceType instanceType, bool isPrimary, bool isSecondary, bool isPassive, bool isArbiter, ReplicaSetInformation replicaSetInformation) { lock (_serverInstanceLock) { bool changed = false; bool replicaSetInformationIsDifferent = false; if ((_replicaSetInformation == null && replicaSetInformation != null) || (_replicaSetInformation != replicaSetInformation)) { replicaSetInformationIsDifferent = true; } if (_state != state || _instanceType != instanceType || replicaSetInformationIsDifferent || _isPrimary != isPrimary || _isSecondary != isSecondary || _isPassive != isPassive || _isArbiter != isArbiter) { changed = true; _state = state; _instanceType = instanceType; if (_replicaSetInformation != replicaSetInformation) { _replicaSetInformation = replicaSetInformation; } _isPrimary = isPrimary; _isSecondary = isSecondary; _isPassive = isPassive; _isArbiter = isArbiter; } if (changed) { if (_state == MongoServerState.Disconnected) { _connectionPool.Clear(); } OnStateChanged(); } } }
/// <summary> /// Sets the state. /// </summary> /// <param name="state">The state.</param> internal void SetState(MongoServerState state) { lock(_serverInstanceLock) { SetState(state, _instanceType, _isPrimary, _isSecondary, _isPassive, _isArbiter, _replicaSetInformation); } }
/// <summary> /// Connects this instance. /// </summary> internal void Connect() { // Console.WriteLine("MongoServerInstance[{0}]: Connect() called.", sequentialId); lock (_serverInstanceLock) { if (_permanentlyDisconnected || _state == MongoServerState.Connecting || _state == MongoServerState.Connected) { return; } _connectException = null; // set the state manually here because SetState raises an event that shouldn't be raised // while holding a lock. _state = MongoServerState.Connecting; } // We know for certain that the state just changed OnStateChanged(); try { var connection = _connectionPool.AcquireConnection(null, null); try { Ping(connection); LookupServerInformation(connection); } finally { _connectionPool.ReleaseConnection(connection); } SetState(MongoServerState.Connected); } catch (Exception ex) { lock (_serverInstanceLock) { _connectException = ex; } _connectionPool.Clear(); Interlocked.Exchange(ref _connectException, ex); SetState(MongoServerState.Disconnected); throw; } finally { lock (_serverInstanceLock) { if (_stateVerificationTimer == null) { _stateVerificationTimer = new Timer(o => StateVerificationTimerCallback(), null, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(10)); } } } }
/// <summary> /// Determines the state of the server. /// </summary> /// <param name="currentState">State of the current.</param> /// <param name="instances">The instances.</param> /// <returns>The state of the server.</returns> protected abstract MongoServerState DetermineServerState(MongoServerState currentState, IEnumerable <MongoServerInstance> instances);
// constructors /// <summary> /// Initializes a new instance of the <see cref="MongoServerInstance"/> class. /// </summary> /// <param name="server">The server.</param> /// <param name="address">The address.</param> internal MongoServerInstance(MongoServer server, MongoServerAddress address) { _server = server; _address = address; _sequentialId = Interlocked.Increment(ref __nextSequentialId); _maxDocumentSize = MongoDefaults.MaxDocumentSize; _maxMessageLength = MongoDefaults.MaxMessageLength; _state = MongoServerState.Disconnected; _instanceType = MongoServerInstanceType.Unknown; _connectionPool = new MongoConnectionPool(this); _pingTimeAggregator = new PingTimeAggregator(5); _stateVerificationTimer = new Timer(o => StateVerificationTimerCallback(), null, TimeSpan.Zero, TimeSpan.FromSeconds(10)); // Console.WriteLine("MongoServerInstance[{0}]: {1}", sequentialId, address); }
/// <summary> /// Sets the state. /// </summary> /// <param name="state">The state.</param> internal void SetState(MongoServerState state) { SetState(state, Interlocked.CompareExchange(ref _stateInfo, null, null)); }