private void SetDescription(ServerDescription newDescription, bool forceClearConnectionPool)
        {
            // Current assumption is SetDescription is always synchronized under _monitor.Lock.
            // This synchronization technically can be violated by calling server.Invalidate not under _monitor.Lock.
            // Therefore _currentDescription and ConnectionPool state can get out of sync.

            var serverDescriptionChangedEvent = new ServerDescriptionChangedEventArgs(_currentDescription, newDescription);

            _currentDescription = newDescription;

            if (newDescription.HeartbeatException != null || forceClearConnectionPool)
            {
                // propagate event to upper levels
                TriggerServerDescriptionChanged(this, serverDescriptionChangedEvent);

                // pool must be cleared on after cluster update
                ConnectionPool.Clear();
            }
            else
            {
                if (newDescription.IsDataBearing ||
                    (newDescription.Type != ServerType.Unknown && IsDirectConnection()))
                {
                    // The spec requires to check (server.type != Unknown and newTopologyDescription.type == Single)
                    // in C# driver servers in single topology will be only selectable if direct connection was requested
                    // therefore it is sufficient to check whether the connection mode is directConnection.

                    ConnectionPool.SetReady();
                }

                // propagate event to upper levels
                TriggerServerDescriptionChanged(this, serverDescriptionChangedEvent);
            }
        }
Esempio n. 2
0
        protected override void HandleBeforeHandshakeCompletesException(Exception ex)
        {
            if (ex is MongoAuthenticationException)
            {
                ConnectionPool.Clear();
                return;
            }

            if (ex is MongoConnectionException mongoConnectionException)
            {
                lock (_monitor.Lock)
                {
                    if (mongoConnectionException.Generation != null &&
                        mongoConnectionException.Generation != ConnectionPool.Generation)
                    {
                        return; // stale generation number
                    }

                    if (mongoConnectionException.IsNetworkException &&
                        !mongoConnectionException.ContainsTimeoutException)
                    {
                        _monitor.CancelCurrentCheck();
                    }

                    if (mongoConnectionException.IsNetworkException || mongoConnectionException.ContainsTimeoutException)
                    {
                        Invalidate($"ChannelException during handshake: {ex}.", clearConnectionPool: true, topologyVersion: null);
                    }
                }
            }
        }
Esempio n. 3
0
        private void OnDescriptionChanged(object sender, ServerDescriptionChangedEventArgs e)
        {
            if (e.NewServerDescription.HeartbeatException != null)
            {
                ConnectionPool.Clear();
            }

            // propagate event to upper levels
            TriggerServerDescriptionChanged(this, e);
        }
Esempio n. 4
0
        protected override void HandleBeforeHandshakeCompletesException(Exception ex)
        {
            // drivers MUST NOT perform SDAM error handling for any errors that occur before the MongoDB Handshake

            if (ex is MongoAuthenticationException mongoAuthenticationException &&
                mongoAuthenticationException.ServiceId.HasValue) // this value will be always filled for MongoAuthenticationException, adding this condition just in case
            {
                // when requiring the connection pool to be cleared, MUST only clear connections for the serviceId.
                ConnectionPool.Clear(mongoAuthenticationException.ServiceId.Value);
            }
        }
Esempio n. 5
0
        // public methods
        public override void Invalidate(string reasonInvalidated, bool clearConnectionPool, TopologyVersion topologyVersion)
        {
            if (clearConnectionPool)
            {
                ConnectionPool.Clear();
            }
            var newDescription = _baseDescription.With(
                $"InvalidatedBecause:{reasonInvalidated}",
                lastUpdateTimestamp: DateTime.UtcNow,
                topologyVersion: topologyVersion);

            SetDescription(newDescription);
            // TODO: make the heartbeat request conditional so we adhere to this part of the spec
            // > Network error when reading or writing: ... Clients MUST NOT request an immediate check of the server;
            // > since application sockets are used frequently, a network error likely means the server has just become
            // > unavailable, so an immediate refresh is likely to get a network error, too.
            RequestHeartbeat();
        }
Esempio n. 6
0
        protected override void HandleAfterHandshakeCompletesException(IConnection connection, Exception ex)
        {
            lock (_connectionPoolLock)
            {
                if (ex is MongoConnectionException mongoConnectionException &&
                    mongoConnectionException.Generation.HasValue &&
                    mongoConnectionException.Generation.Value != ConnectionPool.GetGeneration(connection.Description?.ServiceId))
                {
                    return; // stale generation number
                }

                if (ShouldClearConnectionPoolForChannelException(ex, connection.Description.ServerVersion) &&
                    connection.Description.ServiceId.HasValue) // this value will be always filled in this place, adding this here just in case
                {
                    // when requiring the connection pool to be cleared, MUST only clear connections for the serviceId.
                    ConnectionPool.Clear(connection.Description.ServiceId.Value);
                }
            }
        }