public void ThrowIfExpired_should_not_throw_when_the_timeout_has_not_expired()
        {
            var subject = new SlidingTimeout(TimeSpan.FromSeconds(10), _clock);

            Action act = () => subject.ThrowIfExpired();

            act.ShouldNotThrow();
        }
        // methods
        public async Task AuthenticateAsync(IConnection connection, TimeSpan timeout, CancellationToken cancellationToken)
        {
            using (var conversation = new SaslConversation())
            {
                var currentStep = _mechanism.Initialize(connection);

                var command = new BsonDocument
                {
                    { "saslStart", 1 },
                    { "mechanism", _mechanism.Name },
                    { "payload", currentStep.BytesToSendToServer }
                };

                var slidingTimeout = new SlidingTimeout(timeout);

                while (true)
                {
                    BsonDocument result;
                    try
                    {
                        var protocol = new CommandWireProtocol(new DatabaseNamespace(DatabaseName), command, true, null);
                        result = await protocol.ExecuteAsync(connection, slidingTimeout, cancellationToken);
                    }
                    catch(MongoCommandException ex)
                    {
                        var message = string.Format("Unable to authenticate using sasl protocol mechanism {0}.", Name);
                        throw new MongoAuthenticationException(message, ex);
                    }

                    // we might be done here if the client is not expecting a reply from the server
                    if (result.GetValue("done", false).ToBoolean() && currentStep.IsComplete)
                    {
                        break;
                    }

                    currentStep = currentStep.Transition(conversation, result["payload"].AsByteArray);

                    // we might be done here if the client had some final verification it needed to do
                    if (result.GetValue("done", false).ToBoolean() && currentStep.IsComplete)
                    {
                        break;
                    }

                    command = new BsonDocument
                    {
                        { "saslContinue", 1 },
                        { "conversationId", result["conversationId"].AsInt32 },
                        { "payload", currentStep.BytesToSendToServer }
                    };
                }
            }
        }
        public async Task AuthenticateAsync(IConnection connection, TimeSpan timeout, CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(connection, "connection");

            try
            {
                var slidingTimeout = new SlidingTimeout(timeout);
                var nonce = await GetNonceAsync(connection, slidingTimeout, cancellationToken);
                await AuthenticateAsync(connection, nonce, slidingTimeout, cancellationToken);
            }
            catch(MongoCommandException ex)
            {
                var message = string.Format("Unable to authenticate username '{0}' on database '{1}'.", _credential.Username, _credential.Source);
                throw new MongoAuthenticationException(message, ex);
            }
        }
        public async Task<ConnectionDescription> InitializeConnectionAsync(IConnection connection, ConnectionId connectionId, TimeSpan timeout, CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(connection, "connection");
            Ensure.IsNotNull(connectionId, "connectionId");
            Ensure.IsInfiniteOrGreaterThanOrEqualToZero(timeout, "timeout");

            var slidingTimeout = new SlidingTimeout(timeout);

            var isMasterCommand = new BsonDocument("isMaster", 1);
            var isMasterProtocol = new CommandWireProtocol("admin", isMasterCommand, true);
            var isMasterResult = new IsMasterResult(await isMasterProtocol.ExecuteAsync(connection, slidingTimeout, cancellationToken));

            // authentication is currently broken on arbiters
            if (!isMasterResult.IsArbiter)
            {
                foreach (var authenticator in connection.Settings.Authenticators)
                {
                    await authenticator.AuthenticateAsync(connection, slidingTimeout, cancellationToken);
                }
            }

            var buildInfoCommand = new BsonDocument("buildInfo", 1);
            var buildInfoProtocol = new CommandWireProtocol("admin", buildInfoCommand, true);
            var buildInfoResult = new BuildInfoResult(await buildInfoProtocol.ExecuteAsync(connection, slidingTimeout, cancellationToken));

            var getLastErrorCommand = new BsonDocument("getLastError", 1);
            var getLastErrorProtocol = new CommandWireProtocol("admin", getLastErrorCommand, true);
            var getLastErrorResult = await getLastErrorProtocol.ExecuteAsync(connection, slidingTimeout, cancellationToken);

            BsonValue connectionIdBsonValue;
            if (getLastErrorResult.TryGetValue("connectionId", out connectionIdBsonValue))
            {
                connectionId = connectionId.WithServerValue(connectionIdBsonValue.ToInt32());
            }

            return new ConnectionDescription(connectionId, isMasterResult, buildInfoResult);
        }
        // methods
        public async Task<Stream> CreateStreamAsync(EndPoint endPoint, TimeSpan timeout, CancellationToken cancellationToken)
        {
            var slidingTimeout = new SlidingTimeout(timeout);
            var addressFamily = endPoint.AddressFamily;
            if(addressFamily == AddressFamily.Unspecified || addressFamily == AddressFamily.Unknown)
            {
                addressFamily = _settings.AddressFamily;
            }
            var socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
            await ConnectAsync(socket, endPoint, slidingTimeout, cancellationToken);
            socket.NoDelay = true;
            socket.ReceiveBufferSize = _settings.ReceiveBufferSize;
            socket.SendBufferSize = _settings.SendBufferSize;

            var stream = new NetworkStream(socket, true);

            if (_settings.ReadTimeout.HasValue)
            {
                var readTimeout = (int)_settings.ReadTimeout.Value.TotalMilliseconds;
                if (readTimeout != 0)
                {
                    stream.ReadTimeout = readTimeout;
                }
            }

            if (_settings.WriteTimeout.HasValue)
            {
                var writeTimeout = (int)_settings.WriteTimeout.Value.TotalMilliseconds;
                if (writeTimeout != 0)
                {
                    stream.WriteTimeout = writeTimeout;
                }
            }

            return stream;
        }
        public void Expiration_should_be_DateTime_Max_when_timeout_is_zero()
        {
            var subject = new SlidingTimeout(TimeSpan.Zero);

            subject.Expiration.Should().Be(DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Utc));
        }
        // public methods
        public async Task<IConnectionHandle> AcquireConnectionAsync(TimeSpan timeout, CancellationToken cancellationToken)
        {
            ThrowIfNotOpen();

            var slidingTimeout = new SlidingTimeout(timeout);

            bool enteredWaitQueue = false;
            bool enteredPool = false;

            Stopwatch stopwatch = new Stopwatch();
            try
            {
                if (_listener != null)
                {
                    _listener.ConnectionPoolBeforeEnteringWaitQueue(_serverId);
                }

                stopwatch.Start();
                enteredWaitQueue = _waitQueue.Wait(0); // don't wait...
                if (!enteredWaitQueue)
                {
                    throw new MongoException("Too many waiters in the connection pool.");
                }
                stopwatch.Stop();

                if(_listener != null)
                {
                    _listener.ConnectionPoolAfterEnteringWaitQueue(_serverId, stopwatch.Elapsed);
                    _listener.ConnectionPoolBeforeCheckingOutAConnection(_serverId);
                }

                stopwatch.Restart();
                var waitQueueTimeout = (int)Math.Min(slidingTimeout.ToTimeout().TotalMilliseconds, timeout.TotalMilliseconds);
                if (waitQueueTimeout == Timeout.Infinite)
                {
                    // if one of these is infinite (-1), then we don't timeout properly
                    waitQueueTimeout = (int)Math.Max(slidingTimeout.ToTimeout().TotalMilliseconds, timeout.TotalMilliseconds);
                }
                enteredPool = await _poolQueue.WaitAsync(TimeSpan.FromMilliseconds(waitQueueTimeout), cancellationToken);

                if (enteredPool)
                {
                    var acquired = AcquireConnection();
                    stopwatch.Stop();
                    if (_listener != null)
                    {
                        _listener.ConnectionPoolAfterCheckingOutAConnection(acquired.ConnectionId, stopwatch.Elapsed);
                    }
                    return acquired;
                }

                stopwatch.Stop();
                var message = string.Format("Timed out waiting for a connection after {0}ms.", stopwatch.ElapsedMilliseconds);
                throw new TimeoutException(message);
            }
            catch (Exception ex)
            {
                if (enteredPool)
                {
                    try
                    {
                        _poolQueue.Release();
                    }
                    catch
                    {
                        // TODO: log this, but don't throw... it's a bug if we get here
                    }
                }

                if (_listener != null)
                {
                    if (!enteredWaitQueue)
                    {
                        _listener.ConnectionPoolErrorEnteringWaitQueue(_serverId, stopwatch.Elapsed, ex);
                    }
                    else
                    {
                        _listener.ConnectionPoolErrorCheckingOutAConnection(_serverId, stopwatch.Elapsed, ex);
                    }
                }
                throw;
            }
            finally
            {
                if (enteredWaitQueue)
                {
                    try
                    {
                        _waitQueue.Release();
                    }
                    catch
                    {
                        // TODO: log this, but don't throw... it's a bug if we get here
                    }
                }
            }
        }
        public async Task<BulkWriteResult> ExecuteAsync(IConnectionHandle connection, TimeSpan timeout, CancellationToken cancellationToken)
        {
            var slidingTimeout = new SlidingTimeout(timeout);

            var batchResults = new List<BulkWriteBatchResult>();
            var remainingRequests = new List<WriteRequest>();
            var hasWriteErrors = false;

            var originalIndex = 0;
            foreach (WriteRequest request in _requests)
            {
                if (hasWriteErrors && _isOrdered)
                {
                    remainingRequests.Add(request);
                    continue;
                }

                var batchResult = await EmulateSingleRequestAsync(connection, request, originalIndex, slidingTimeout, cancellationToken);
                batchResults.Add(batchResult);

                hasWriteErrors |= batchResult.HasWriteErrors;
                originalIndex++;
            }

            var combiner = new BulkWriteBatchResultCombiner(batchResults, !_writeConcern.Equals(WriteConcern.Unacknowledged));
            return combiner.CreateResultOrThrowIfHasErrors(remainingRequests);
        }
        public void ToTimeout_should_return_infinite_TimeSpan_when_expiration_is_MaxValue()
        {
            var subject = new SlidingTimeout(Timeout.InfiniteTimeSpan);

            subject.ToTimeout().Should().Be(Timeout.InfiniteTimeSpan);
        }
        public void Expiration_should_be_DateTime_Max_when_timeout_is_infinite()
        {
            var subject = new SlidingTimeout(Timeout.InfiniteTimeSpan);

            subject.Expiration.Should().Be(DateTime.SpecifyKind(DateTime.MaxValue, DateTimeKind.Utc));
        }
        public void Expiration_should_be_UtcNow_plus_timeout()
        {
            var subject = new SlidingTimeout(TimeSpan.FromSeconds(10), _clock);

            subject.Expiration.Should().Be(_clock.UtcNow.AddSeconds(10));
        }
        public void ThrowIfExpired_should_throw_when_the_timeout_has_expired()
        {
            var subject = new SlidingTimeout(TimeSpan.FromSeconds(10), _clock);
            _clock.UtcNow = _clock.UtcNow.AddSeconds(11);

            Action act = () => subject.ThrowIfExpired();

            act.ShouldThrow<TimeoutException>();
        }
        public void Expiration_should_be_UtcNow_plus_timeout()
        {
            var subject = new SlidingTimeout(TimeSpan.FromSeconds(10), _clock);

            subject.Expiration.Should().Be(_clock.UtcNow.AddSeconds(10));
        }
        public void ToTimeout_should_return_infinite_TimeSpan_when_expiration_is_MaxValue()
        {
            var subject = new SlidingTimeout(Timeout.InfiniteTimeSpan);

            subject.ToTimeout().Should().Be(Timeout.InfiniteTimeSpan);
        }
        public void ToTimeout_should_throw_a_TimeoutException_when_the_timeout_has_expired()
        {
            var subject = new SlidingTimeout(TimeSpan.FromMilliseconds(20), _clock);

            _clock.UtcNow = _clock.UtcNow.AddMilliseconds(30);

            Action act = () => subject.ToTimeout();

            act.ShouldThrow<TimeoutException>();
        }
        public void ToTimeout_should_return_the_amount_of_time_left()
        {
            var subject = new SlidingTimeout(TimeSpan.FromMilliseconds(20), _clock);

            subject.ToTimeout().Should().Be(TimeSpan.FromMilliseconds(20));

            _clock.UtcNow = _clock.UtcNow.AddMilliseconds(10);

            subject.ToTimeout().Should().Be(TimeSpan.FromMilliseconds(10));

            _clock.UtcNow = _clock.UtcNow.AddMilliseconds(10);

            subject.ToTimeout().Should().Be(TimeSpan.Zero);
        }
Esempio n. 17
0
        public async Task<IServer> SelectServerAsync(IServerSelector selector, TimeSpan timeout, CancellationToken cancellationToken)
        {
            ThrowIfDisposedOrNotOpen();
            Ensure.IsNotNull(selector, "selector");
            var slidingTimeout = new SlidingTimeout(timeout);

            while (true)
            {
                cancellationToken.ThrowIfCancellationRequested();

                Task descriptionChangedTask;
                ClusterDescription description;
                lock (_descriptionLock)
                {
                    descriptionChangedTask = _descriptionChangedTaskCompletionSource.Task;
                    description = _description;
                }

                ThrowIfIncompatible(description);

                var connectedServers = description.Servers.Where(s => s.State == ServerState.Connected);
                var selectedServers = selector.SelectServers(description, connectedServers).ToList();

                while (selectedServers.Count > 0)
                {
                    var server = selectedServers.Count == 1 ?
                        selectedServers[0] :
                        __randomServerSelector.SelectServers(description, selectedServers).Single();

                    IClusterableServer selectedServer;
                    if (TryGetServer(server.EndPoint, out selectedServer))
                    {
                        return selectedServer;
                    }

                    selectedServers.Remove(server);
                }

                Invalidate();

                await descriptionChangedTask.WithTimeout(slidingTimeout, cancellationToken);
            }
        }