/// <summary>
        /// Handles the reconnection attempts.
        /// If it succeeds, it marks the host as UP.
        /// If not, it marks the host as DOWN
        /// </summary>
        internal void AttemptReconnection()
        {
            _poolModificationSemaphore.Wait();
            var toRemove = _connections.Where(c => c.IsClosed).ToArray();

            foreach (var c in toRemove)
            {
                _connections.Remove(c);
            }
            if (_connections.Count > 0)
            {
                //there is already an open connection
                _poolModificationSemaphore.Release();
                return;
            }
            Logger.Info("Attempting reconnection to host {0}", _host.Address);
            CreateConnection().ContinueWith(t =>
            {
                if (t.Status == TaskStatus.RanToCompletion)
                {
                    _connections.Add(t.Result);
                    //Release as soon as possible
                    _poolModificationSemaphore.Release();
                    Logger.Info("Reconnection attempt to host {0} succeeded", _host.Address);
                    _host.BringUpIfDown();
                }
                else
                {
                    _poolModificationSemaphore.Release();
                    Logger.Info("Reconnection attempt to host {0} failed", _host.Address);
                    _host.SetDown();
                }
            }, TaskContinuationOptions.ExecuteSynchronously);
        }
Beispiel #2
0
        /// <summary>
        /// Handles the reconnection attempts.
        /// If it succeeds, it marks the host as UP.
        /// If not, it marks the host as DOWN
        /// </summary>
        internal void AttemptReconnection()
        {
            _isShuttingDown = false;
            if (_isDisposed)
            {
                return;
            }
            var tcs = new TaskCompletionSource <Connection[]>();
            //While there is a single thread here, there might be another thread
            //Calling MaybeCreateFirstConnection()
            //Guard for multiple creations
            var creationTcs = Interlocked.CompareExchange(ref _creationTcs, tcs, null);

            if (creationTcs != null || _connections.Count > 0)
            {
                //Already creating as host is back UP (possibly via events)
                return;
            }
            Logger.Info("Attempting reconnection to host {0}", _host.Address);
            //There is a single thread creating a connection
            CreateConnection().ContinueWith(t =>
            {
                if (t.Status == TaskStatus.RanToCompletion)
                {
                    if (_isShuttingDown)
                    {
                        t.Result.Dispose();
                        TransitionCreationTask(tcs, EmptyConnectionsArray);
                        return;
                    }
                    _connections.Add(t.Result);
                    Logger.Info("Reconnection attempt to host {0} succeeded", _host.Address);
                    _host.BringUpIfDown();
                    TransitionCreationTask(tcs, new [] { t.Result });
                    return;
                }
                Logger.Info("Reconnection attempt to host {0} failed", _host.Address);
                Exception ex = null;
                if (t.Exception != null)
                {
                    t.Exception.Handle(e => true);
                    ex = t.Exception.InnerException;
                    //This makes sure that the exception is observed, but still sets _creationTcs' exception
                    //for MaybeCreateFirstConnection
                    tcs.Task.ContinueWith(x =>
                    {
                        if (x.Exception != null)
                        {
                            x.Exception.Handle(_ => true);
                        }
                    });
                }
                TransitionCreationTask(tcs, EmptyConnectionsArray, ex);
                _host.SetDown(failedReconnection: true);
            }, TaskContinuationOptions.ExecuteSynchronously);
        }
Beispiel #3
0
        /// <summary>
        /// Asynchronously starts to create a new connection (if its not already being created).
        /// A <c>null</c> schedule signals that the pool is not reconnecting but growing to the expected size.
        /// </summary>
        /// <param name="schedule"></param>
        private void StartCreatingConnection(IReconnectionSchedule schedule)
        {
            var count = _connections.Count;

            if (count >= _expectedConnectionLength)
            {
                return;
            }
            if (schedule != null && schedule != _reconnectionSchedule)
            {
                // There's another reconnection schedule, leave it
                return;
            }
            CreateOpenConnection(false).ContinueWith(t =>
            {
                if (t.Status == TaskStatus.RanToCompletion)
                {
                    StartCreatingConnection(null);
                    _host.BringUpIfDown();
                    return;
                }
                t.Exception?.Handle(_ => true);
                // The connection could not be opened
                if (IsClosing)
                {
                    // don't mind, the pool is not supposed to be open
                    return;
                }
                if (schedule == null)
                {
                    // As it failed, we need a new schedule for the following attempts
                    schedule = _config.Policies.ReconnectionPolicy.NewSchedule();
                    _reconnectionSchedule = schedule;
                }
                if (schedule != _reconnectionSchedule)
                {
                    // There's another reconnection schedule, leave it
                    return;
                }
                OnConnectionClosing();
            }, TaskContinuationOptions.ExecuteSynchronously);
        }
        /// <summary>
        /// Gets a connection from the next host according to the load balancing policy
        /// </summary>
        /// <exception cref="NoHostAvailableException"/>
        /// <exception cref="InvalidQueryException">When keyspace does not exist</exception>
        /// <exception cref="UnsupportedProtocolVersionException"/>
        internal Connection GetNextConnection(IStatement statement, bool isLastChance = false)
        {
            var  hostEnumerable = _session.Policies.LoadBalancingPolicy.NewQueryPlan(statement);
            Host lastChanceHost = null;

            //hostEnumerable GetEnumerator will return a NEW enumerator, making this call thread safe
            foreach (var host in hostEnumerable)
            {
                if (!host.IsConsiderablyUp)
                {
                    if (!isLastChance && host.Resurrect)
                    {
                        lastChanceHost = host;
                    }
                    continue;
                }
                _currentHost = host;
                _triedHosts[host.Address] = null;
                Connection connection = null;
                try
                {
                    var distance = _session.Policies.LoadBalancingPolicy.Distance(host);
                    var hostPool = _session.GetConnectionPool(host, distance);
                    connection = hostPool.BorrowConnection();
                    if (connection == null)
                    {
                        continue;
                    }
                    connection.Keyspace = _session.Keyspace;
                    return(connection);
                }
                catch (SocketException ex)
                {
                    _session.SetHostDown(host, connection);
                    _triedHosts[host.Address] = ex;
                    host.Resurrect            = CanBeResurrected(ex, connection);
                    if (!isLastChance && host.Resurrect)
                    {
                        lastChanceHost = host;
                    }
                }
                catch (InvalidQueryException)
                {
                    //The keyspace does not exist
                    throw;
                }
                catch (UnsupportedProtocolVersionException)
                {
                    //The version of the protocol is not supported
                    throw;
                }
                catch (Exception ex)
                {
                    _logger.Error(ex);
                    _triedHosts[host.Address] = ex;
                }
            }
            _currentHost = null;
            if (lastChanceHost != null)
            {
                //There are no host available and some of them are due to network events.
                //Probably there was a network event that reset all connections and it does not mean the connection
                _logger.Warning("Suspected network reset. Getting one host up and retrying for a last chance");
                lastChanceHost.BringUpIfDown();
                return(GetNextConnection(statement, true));
            }
            throw new NoHostAvailableException(_triedHosts);
        }