예제 #1
0
 /// <summary>
 /// Creates a new instance of the AsyncResponse class, that serves as a state object during execution of the
 /// request and fully documented Request/Response data structure for the callback method.
 /// </summary>
 /// <param name="executor">Reference to the connection that will execute the request.</param>
 /// <param name="executionId">The reference id for the execution request.</param>
 /// <param name="timeout">Execution timeout for the request.</param>
 /// <param name="callback">The callback to execute upon completion.</param>
 /// <param name="state">A user-defined object that qualifies or contains information about an asynchronous
 /// operation.</param>
 /// <param name="procedure">The procedure to execute on the server.</param>
 /// <param name="parameters">The parameters passed to the procedure.</param>
 internal AsyncResponse(
     VoltNodeConnection executor
     , long executionId
     , int timeout
     , ExecuteAsyncCallback <TResult> callback
     , object state
     , string procedure
     , params object[] parameters
     )
     : base(executor, executionId, timeout, procedure, parameters)
 {
     this.Callback    = callback;
     this._AsyncState = state;
 }
예제 #2
0
 /// <summary>
 /// Creates a new instance of the AsynResponseBase class.
 /// </summary>
 /// <param name="executor">Reference to the connection that will execute the request.</param>
 /// <param name="executionId">The reference id for the execution request.</param>
 /// <param name="timeout">Execution timeout for the request.</param>
 /// <param name="procedure">The procedure to execute on the server.</param>
 /// <param name="parameters">The parameters passed to the procedure.</param>
 internal Response(VoltNodeConnection executor, long executionId, int timeout, string procedure, params object[] parameters)
 {
     this.Executor    = executor;
     this.ExecutionId = executionId;
     this.Procedure   = procedure;
     this.Parameters  = parameters;
     // Initialize execution duration to timeout - this will be the case if the request times out, otherwise
     // the value will be overwritten when the server message is parsed out.
     this.ExecutionDuration = timeout;
     this.ExpirationTicks   = (
         timeout == -1
                            ? DateTime.UtcNow.AddDays(1)
                            : DateTime.UtcNow.AddMilliseconds(timeout)
         ).Ticks;
 }
예제 #3
0
 /// <summary>
 /// Creates a new instance of the AsynResponseBase class.
 /// </summary>
 /// <param name="executor">Reference to the connection that will execute the request.</param>
 /// <param name="executionId">The reference id for the execution request.</param>
 /// <param name="timeout">Execution timeout for the request.</param>
 /// <param name="procedure">The procedure to execute on the server.</param>
 /// <param name="parameters">The parameters passed to the procedure.</param>
 internal Response(VoltNodeConnection executor, long executionId, int timeout, string procedure, params object[] parameters)
 {
     this.Executor = executor;
     this.ExecutionId = executionId;
     this.Procedure = procedure;
     this.Parameters = parameters;
     // Initialize execution duration to timeout - this will be the case if the request times out, otherwise
     // the value will be overwritten when the server message is parsed out.
     this.ExecutionDuration = timeout;
     this.ExpirationTicks = (
                              timeout == -1
                            ? DateTime.UtcNow.AddDays(1)
                            : DateTime.UtcNow.AddMilliseconds(timeout)
                            ).Ticks;
 }
        /// <summary>
        /// Provides a background thread to reconnect failed node connections.
        /// </summary>
        /// <param name="state">The connection to re-open</param>
        private void ReconnectChildConnection(object state)
        {
            // Get connection object from the state object passed by the thread pool.
            VoltNodeConnection connection = state as VoltNodeConnection;

            // Try to reconnect until the connection is actively closed by the user or terminated (when all child
            // connections died and none could be re-opened)
            while (this.Status == ConnectionStatus.Connected)
            {
                try
                {
                    // Attempt to open the connection
                    connection.Open();

                    // If somebody tried to swap out the node from under us to start a different cluster, return
                    // immediately: we will not reconnect there!
                    if (
                        (this.BuildString != connection.BuildString) ||
                        (!this.LeaderIPEndPoint.Equals(connection.LeaderIPEndPoint)) ||
                        (this.ClusterStartTimeStamp != connection.ClusterStartTimeStamp)
                        )
                    {
                        connection.Terminate();
                        return;
                    }

                    // Refresh pool status to re-enlist the connection into active duty.
                    this.RefreshConnectionPoolStatus();

                    // End the thread: connection successfully re-added to the pool.
                    return;
                }
                catch
                {
                    // Sleep a while to give the node time to rejoin if needed.
                    Thread.Sleep(this.Settings.ConnectionTimeout);
                }
            }
        }
        /// <summary>
        /// Async sub-connection opening - open a child connection and add to the pool when successful.
        /// </summary>
        /// <param name="settings">Settings to use for the child connection to open.</param>
        private void OpenChildConnection(ConnectionSettings settings)
        {
            // Return immediately if there was a terminal connection failure on any of the parallel attempts.
            if (Interlocked.Read(ref this.ConnectionExceptionCount) > 0)
            {
                return;
            }

            try
            {
                // Try to open the node connection.
                VoltNodeConnection connection = new VoltNodeConnection(settings, this.CallbackExecutor);
                connection.Open();

                // Lock the connection pool for validation and addition.
                lock ((this.ConnectionPool as IList).SyncRoot)
                {
                    // Validate new node against previous connections: we will refuse any connection to an inconsistent
                    // cluster (different versions, different application, etc).
                    if (this.ConnectionPool.Count > 0)
                    {
                        if (
                            (this.BuildString != connection.BuildString) ||
                            (!this.LeaderIPEndPoint.Equals(connection.LeaderIPEndPoint)) ||
                            (this.ClusterStartTimeStamp != connection.ClusterStartTimeStamp)
                            )
                        {
                            // This node doesn't belong to the cluster - terminate the connection and throw out!
                            try
                            {
                                connection.Terminate();
                            }
                            catch {}

                            throw new VoltClusterConnectionException(
                                      Resources.InconsistentClusterTarget

                                      , string.Join("\r\n"
                                                    , this.ConnectionPool.Select(i =>
                                                                                 string.Format(
                                                                                     Resources.InconsistentClusterTargetListing
                                                                                     , i.ServerHostId
                                                                                     , i.ConnectionId
                                                                                     , i.IPEndPoint
                                                                                     , i.LeaderIPEndPoint
                                                                                     , i.ClusterStartTimeStamp
                                                                                     , i.BuildString
                                                                                     )
                                                                                 ).ToArray()
                                                    )

                                      , string.Format(
                                          Resources.InconsistentClusterTargetListing
                                          , connection.ServerHostId
                                          , connection.ConnectionId
                                          , connection.IPEndPoint
                                          , connection.LeaderIPEndPoint
                                          , connection.ClusterStartTimeStamp
                                          , connection.BuildString
                                          )

                                      );
                        }
                    }
                    else
                    {
                        // Grab cluster details after the first connection to compare future connections against.
                        this.BuildString           = connection.BuildString;
                        this.ClusterStartTimeStamp = connection.ClusterStartTimeStamp;
                        this.LeaderIPEndPoint      = connection.LeaderIPEndPoint;
                    }
                    // Connection is valid, add it to the pool
                    this.ConnectionPool.Add(connection);
                }
            }
            catch (Exception x)
            {
                // Flag terminal exceptions: in this case we do NOT want to proceed no matter if a single node ever
                // replied.
                if ((x is VoltClusterConnectionException) || this.Settings.ConnectToAllOrNone)
                {
                    Interlocked.Increment(ref this.ConnectionExceptionCount);
                }

                // Add the exception to the list for later reporting.
                lock ((this.ConnectionExceptionList as IList).SyncRoot)
                    this.ConnectionExceptionList.Add(x);
            }
        }