/// <summary>
        /// Blocks the calling thread until the queue of pending responses is fully exhausted (all responses received
        /// by the server).
        /// </summary>
        /// <returns>A reference to the current connection instance for action chaining.</returns>
        public override VoltConnection Drain()
        {
            // Synchronize access - this will take another lock if the call originates from "Close", but it actually
            // won't: the lock's owning thread will fly through since it owns the lock - everybody else will be stuck.
            lock (this.SyncRoot)
            {
                // Validate connection status.
                if (!((this.Status == ConnectionStatus.Connected) || (this.Status == ConnectionStatus.Closing)))
                {
                    throw new InvalidOperationException(string.Format(Resources.InvalidConnectionStatus, this.Status));
                }

                // Trace as needed.
                if (this.Settings.TraceEnabled)
                {
                    VoltTrace.TraceEvent(
                        TraceEventType.Information
                        , VoltTraceEventType.DrainingStarted
                        , Resources.TraceClusterConnectionDrainingStarted
                        );
                }

                // Cache current status to resore later.
                ConnectionStatus previousStatus = this.Status;

                //Change status and perform draining.
                this.Status = ConnectionStatus.Draining;


                // In concept, this should really be parallelized but who really cares?  The cluster will refuse all
                // connections, so that by not submitting more work we ARE draining all the children anyways.
                // Thus the wait will still be = Max-Drain-Duration-for-slowest-host.
                foreach (VoltNodeConnection connection in this.ConnectionPool)
                {
                    // Sub-connection might have died, in which case there won't be anything to do, but we need to make
                    // sure we won't die on the exception it will raise!
                    try
                    {
                        connection.Drain();
                    }
                    catch { }
                }

                // Restore status.
                this.Status = previousStatus;

                // Trace as needed.
                if (this.Settings.TraceEnabled)
                {
                    VoltTrace.TraceEvent(
                        TraceEventType.Information
                        , VoltTraceEventType.DrainingCompleted
                        , Resources.TraceClusterConnectionDrainingCompleted
                        );
                }
            }
            return(this);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Blocks the calling thread until the queue of pending responses is fully exhausted (all responses received
        /// by the server).
        /// </summary>
        /// <returns>A reference to the current connection instance for action chaining.</returns>
        public override VoltConnection Drain()
        {
            // Synchronize access - this will take another lock if the call originates from "Close", but it actually
            // won't: the lock's owning thread will fly through since it owns the lock - everybody else will be stuck.
            lock (this.SyncRoot)
            {
                // Validate connection status.
                if (!((this.Status == ConnectionStatus.Connected) || (this.Status == ConnectionStatus.Closing)))
                {
                    throw new InvalidOperationException(string.Format(Resources.InvalidConnectionStatus, this.Status));
                }

                // Trace as needed.
                if (this.Settings_TraceEnabled)
                {
                    VoltTrace.TraceEvent(
                        TraceEventType.Information
                        , VoltTraceEventType.DrainingStarted
                        , Resources.TraceConnectionDrainingStarted
                        , this.ServerHostId
                        , this.ConnectionId
                        );
                }

                // Cache current status to resore later.
                ConnectionStatus previousStatus = this.Status;

                //Change status and perform draining.
                this.Status = ConnectionStatus.Draining;
                while (this.ExecutionCache.Size > 0)
                {
                    Thread.Sleep(100);
                }
                // Restore status.
                this.Status = previousStatus;

                // Trace as needed.
                if (this.Settings_TraceEnabled)
                {
                    VoltTrace.TraceEvent(
                        TraceEventType.Information
                        , VoltTraceEventType.DrainingCompleted
                        , Resources.TraceConnectionDrainingCompleted
                        , this.ServerHostId
                        , this.ConnectionId
                        );
                }
            }
            return(this);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Provides a hookup on internal completetion of procedure calls (used by derived classes for performance
        /// monitoring and tracing.
        /// </summary>
        /// <param name="executionId">The execution id of the request that was just completed.</param>
        /// <param name="procedure">The name of the procedure that was run.</param>
        /// <param name="executionDuration">The duration of the execution that was just completed.</param>
        /// <param name="status">The status of the execution request's response.</param>
        /// <param name="bytesReceived">Size of the response, in bytes, for network I/O tracking.</param>
        internal void OnExecutionComplete(
            long executionId
            , string procedure
            , int executionDuration
            , ResponseStatus status
            , long bytesReceived
            )
        {
            // TODO: Revise network tracking so that dropped (timeout or cancel) responses are still tracked adequately
            // Track statistics as needed.
            TrackStatisticsCloseRequest(executionId, procedure, executionDuration, status, bytesReceived);

            // Trace as needed.
            if (this.Settings_TraceEnabled)
            {
                VoltTrace.TraceEvent(
                    status != ResponseStatus.Success
                                      ? TraceEventType.Error
                                      : TraceEventType.Information

                    , status == ResponseStatus.Timedout
                                      ? VoltTraceEventType.ExecutionTimedout
                                      : status == ResponseStatus.Failed
                                        ? VoltTraceEventType.ExecutionFailed
                                        : status == ResponseStatus.Aborted
                                          ? VoltTraceEventType.ExecutionAborted
                                          : VoltTraceEventType.ExecutionCompleted

                    , status == ResponseStatus.Timedout
                                      ? Resources.TraceExecutionTimedout
                                      : status == ResponseStatus.Failed
                                        ? Resources.TraceExecutionFailed
                                        : status == ResponseStatus.Aborted
                                          ? Resources.TraceExecutionAborted
                                          : Resources.TraceExecutionCompleted

                    , this.ServerHostId
                    , this.ConnectionId
                    , executionId
                    , procedure
                    , executionDuration
                    );
            }

            // Confirm the item as removed in the execution cache.
            this.ExecutionCache.EndRemoveItem();
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Closes the connection, optionally waiting for all pending responses to have been received.
        /// </summary>
        /// <param name="drain">True/false: whether to wait for all responses to be processed before terminating
        /// the connection.</param>
        /// <returns>A reference to the current connection instance for action chaining.</returns>
        public override VoltConnection Close(bool drain)
        {
            // Synchronize access.
            lock (this.SyncRoot)
            {
                // Validate connection status.
                if (this.Status != ConnectionStatus.Connected)
                {
                    throw new InvalidOperationException(string.Format(Resources.InvalidConnectionStatus, this.Status));
                }

                // Trace as needed.
                if (this.Settings_TraceEnabled)
                {
                    VoltTrace.TraceEvent(
                        TraceEventType.Information
                        , VoltTraceEventType.ConnectionClosing
                        , Resources.TraceConnectionClosing
                        , this.ServerHostId
                        , this.ConnectionId
                        );
                }

                // Set status
                this.Status = ConnectionStatus.Closing;

                // Drain first if requested.
                if (drain)
                {
                    this.Drain();
                }

                // Terminate the connection (trace event for final closure will be posted there).
                this.Terminate();
            }
            return(this);
        }
        /// <summary>
        /// Closes the connection, optionally waiting for all pending responses to have been received.
        /// </summary>
        /// <param name="drain">True/false: whether to wait for all responses to be processed before terminating the
        /// connection.</param>
        /// <returns>A reference to the current connection instance for action chaining.</returns>
        public override VoltConnection Close(bool drain)
        {
            // Synchronize access.
            lock (this.SyncRoot)
            {
                try
                {
                    // Validate connection status.
                    if (this.Status != ConnectionStatus.Connected)
                    {
                        throw new InvalidOperationException(
                                  string.Format(
                                      Resources.InvalidConnectionStatus
                                      , this.Status
                                      )
                                  );
                    }

                    // Trace as needed.
                    if (this.Settings.TraceEnabled)
                    {
                        VoltTrace.TraceEvent(
                            TraceEventType.Information
                            , VoltTraceEventType.ConnectionClosing
                            , Resources.TraceClusterConnectionClosing
                            );
                    }

                    // Set status.
                    this.Status = ConnectionStatus.Closing;

                    // Drain first if requested (we do not call the child's CLose(drain) method because we want to make
                    // sure tracing at the top level is consistent).
                    if (drain)
                    {
                        this.Drain();
                    }

                    // Close connections
                    foreach (VoltNodeConnection connection in this.ConnectionPool)
                    {
                        // Sub-connection might have died, in which case there won't be anything to do, but we need to
                        // make sure we won't die on the exception it will raise!
                        try
                        {
                            connection.Close(false);
                        }
                        catch { }
                    }

                    // Stop the callback executor's threads.  This will also drain callback execution, ensuring every
                    // triggered callback actually gets executed before the executor is shut down.
                    this.CallbackExecutor.Stop();

                    // Trace as needed.
                    if (this.Settings.TraceEnabled)
                    {
                        VoltTrace.TraceEvent(
                            TraceEventType.Information
                            , VoltTraceEventType.ConnectionClosed
                            , Resources.TraceClusterConnectionClosed
                            );
                    }
                }
                finally
                {
                    // Mark connection as closed
                    this.Status = ConnectionStatus.Closed;
                }
            }
            return(this);
        }
        /// <summary>
        /// Open the cluster connections: the provided settings are analyzed to deploy a full list of IP Endpoints
        /// (IP:port) of nodes to which we should connect.  Child connections are then opened in parallel to all those
        /// endpoints.  Depending on your settings and the cluster configuration, a failure can mean the "Open" method
        /// will fail (and throw details about the errors encountered), or move forth (all connections opened, of
        /// course; but also in cases where the configuration indicates that a partial connection is valid, the
        /// connection will be allowed to stay available).
        /// </summary>
        /// <returns>A reference to the current connection instance for action chaining.</returns>
        public override VoltConnection Open()
        {
            lock (this.SyncRoot)
            {
                // Validate connection status.
                if (this.Status != ConnectionStatus.Closed)
                {
                    throw new InvalidOperationException(string.Format(Resources.InvalidConnectionStatus, this.Status));
                }

                // Set status to "connecting".
                this.Status = ConnectionStatus.Connecting;

                try
                {
                    // Deploy the connection settings into individual IPEndPoint connections.
                    ConnectionSettings[] clusterSettings = this.Settings.ClusterConnectionSettings;

                    // Create delegate for invokation.
                    OpenChildConnectionDelegate handler = this.OpenChildConnection;

                    // Empty the connection list if this is happening after a close event.
                    this.ConnectionPool.Clear();
                    this.ConnectionCount = 0;

                    // Reset connection monitoring flags.
                    this.ConnectionExceptionList  = new List <Exception>();
                    this.ConnectionExceptionCount = 0;

                    // Prepare async operation - we open connections in parallel (as much as the system will allow,
                    // that is by blocks of 64 maximum - the size limit for a WaitHandle[] that WaitAll will accept).
                    for (int batchStart = 0; batchStart < clusterSettings.Length; batchStart += 64)
                    {
                        int batchLength = Math.Min(clusterSettings.Length - batchStart, 64);

                        // Create a block of wait handles.
                        WaitHandle[] waitHandles = new WaitHandle[batchLength];

                        // Kick off connection.Open requests - finalization will be processed in parallel as well.
                        // We will check the results after al threads have returned or a timeout.
                        // Now technically, since we're doing this in batches of 64, if we have 65 connections, it
                        // means we will wait for the first 64 connections to be open (or fail to open) before trying
                        // out for the 65th.  Not ideal, but probably not a case to seriously worry about.
                        for (int sourceIndex = batchStart; sourceIndex < batchLength + batchStart; sourceIndex++)
                        {
                            IAsyncResult ar = handler.BeginInvoke(clusterSettings[sourceIndex], null, handler);
                            waitHandles[sourceIndex - batchStart] = ar.AsyncWaitHandle;
                        }

                        // Now wait for all connections to complete before proceeding to check the results.
                        if (!WaitHandle.WaitAll(
                                waitHandles
                                , this.Settings.ConnectionTimeout == Timeout.Infinite
                                                 ? Timeout.Infinite
                                                 : this.Settings.ConnectionTimeout * batchLength)
                            )
                        {
                            // At least one of the connections timeout.  If we're in "ConnectToAllOrNone" mode, trigger
                            // termination.
                            if (this.Settings.ConnectToAllOrNone)
                            {
                                lock ((this.ConnectionPool as IList).SyncRoot)
                                    throw new VoltClusterConnectionException(
                                              Resources.ClusterConnectionTimeout
                                              , string.Join("\r\n"
                                                            , clusterSettings.Select(r =>
                                                                                     string.Format(
                                                                                         Resources.ClusterConnectionSummaryRow
                                                                                         , r.DefaultIPEndPoint
                                                                                         , this.ConnectionPool
                                                                                         .Exists(c => c.IPEndPoint.Equals(r.DefaultIPEndPoint))
                                                                                         )
                                                                                     ).ToArray()
                                                            )
                                              );
                            }
                        }

                        // Check the results.
                        if (this.ConnectionExceptionCount > 0)
                        {
                            // Aggregate all the exceptions to feed to the user.
                            lock ((this.ConnectionExceptionList as IList).SyncRoot)
                                throw new VoltClusterConnectionException(
                                          Resources.ClusterConnectionFailure
                                          , string.Join("\r\n\r\n"
                                                        , this.ConnectionExceptionList.Select(x => x.ToString()).ToArray()
                                                        )
                                          );
                        }
                    }

                    // If we get here, all connections were successfully open (or in the case we're not in "All or
                    // nothing", some did - or did they?  Make sure we have at least one!
                    if (this.ConnectionPool.Count < 1)
                    {
                        throw new VoltClusterConnectionException(Resources.ClusterConnectionFailureNoSingleHost
                                                                 , string.Join("\r\n\r\n", this.ConnectionExceptionList.Select(x => x.ToString()).ToArray()));
                    }

                    // Record connection count for multiplexing.
                    this.ConnectionCount = this.ConnectionPool.Count;

                    // Initialize map of live connections - at the beginning, obviously, they are all alive.
                    // This array contains the list of Indexes of the live connections.  For instance, if connection
                    // #2 where to die on a cluster of 3 connections , the array would be modified to: [1,3].
                    // Multiplexing will then load balance between those two, while the dead connection is left in the
                    // pool for possible recovery and statistical history support.
                    this.LiveConnectionIndexList = new int[this.ConnectionCount];
                    for (int i = 0; i < this.ConnectionCount; i++)
                    {
                        this.LiveConnectionIndexList[i] = i;
                    }


                    // Looking good... Set status to "connected".
                    this.Status = ConnectionStatus.Connected;

                    // Trace as needed.
                    if (this.Settings.TraceEnabled)
                    {
                        VoltTrace.TraceEvent(
                            TraceEventType.Information
                            , VoltTraceEventType.ConnectionOpened
                            , Resources.TraceClusterConnectionOpened
                            , this.LeaderIPEndPoint
                            , this.ClusterStartTimeStamp
                            , this.BuildString
                            , string.Join("\r\n"
                                          , clusterSettings.Select(r =>
                                                                   string.Format(Resources.ClusterConnectionSummaryRow
                                                                                 , r.DefaultIPEndPoint
                                                                                 , this.ConnectionPool
                                                                                 .Exists(c => c.IPEndPoint.Equals(r.DefaultIPEndPoint))
                                                                                 )
                                                                   ).ToArray()
                                          )
                            );
                    }
                }
                catch (Exception x)
                {
                    try
                    {
                        // In case of failure, terminate everything immediately (will correct status)
                        try
                        {
                            // No waiting, no nothing: it's over - Terminate sub-connections (Terminate swallows any
                            // exception, so this is safe without try/catch).
                            foreach (VoltNodeConnection connection in this.ConnectionPool)
                            {
                                connection.Terminate();
                            }
                            this.ConnectionPool.Clear();

                            // Trace as needed
                            if (this.Settings.TraceEnabled)
                            {
                                VoltTrace.TraceEvent(
                                    TraceEventType.Information
                                    , VoltTraceEventType.ConnectionClosed
                                    , Resources.TraceClusterConnectionClosed
                                    );
                            }
                        }
                        finally
                        {
                            this.ConnectionPool.Clear();
                            this.Status = ConnectionStatus.Closed;
                        }
                    }
                    catch { }
                    // Re-throw exception, wrapping if needed.
                    if (x is VoltException)
                    {
                        throw new VoltConnectionException(Resources.ClusterConnectionUnknownFailure, x);
                    }
                    else
                    {
                        throw x;
                    }
                }
            }
            return(this);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Open the connection.
        /// </summary>
        /// <returns>A reference to the current connection instance for action chaining.</returns>
        public override VoltConnection Open()
        {
            // Synchronize access.
            lock (this.SyncRoot)
            {
                // Validate connection status.
                if (this.Status != ConnectionStatus.Closed)
                {
                    throw new InvalidOperationException(string.Format(Resources.InvalidConnectionStatus, this.Status));
                }

                // Set status to "connecting".
                this.Status = ConnectionStatus.Connecting;

                // Connect to the default endpoint (there should only be one anyways if this is a managed pool
                // connection, otherwise, you're on your own - this is a connection, not a Pool!).
                IPEndPoint endPoint = this.Settings.DefaultIPEndPoint;
                try
                {
                    // Create new socket stream and wrap a core protocol stream manager around it.
                    this.BaseStream = new VoltProtocolStream(endPoint, this.Settings.ConnectionTimeout);

                    // Now send login message.
                    using (Serializer serializer = new Serializer())
                    {
                        var msg = serializer
                                  .Write(this.Settings.ServiceType.ToString().ToLowerInvariant())
                                  .Write(this.Settings.UserID)
                                  .WriteRaw(SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(this.Settings.Password)))
                                  .GetBytes();
                        this.BaseStream.WriteMessage(msg.Array, msg.Offset, msg.Count);
                    }

                    // Receive and process login response message.
                    var deserializer           = new Deserializer(this.BaseStream.ReadMessage());
                    LoginResponseStatus status = (LoginResponseStatus)deserializer.ReadSByte();
                    if (status != LoginResponseStatus.Connected)
                    {
                        // Re-package server response in an appropriate exception.
                        switch (status)
                        {
                        case LoginResponseStatus.ConnectionHandshakeTimeout:
                            throw new VoltConnectionException(
                                      Resources.LRS_ConnectionHandshakeTimeout
                                      , endPoint
                                      , status
                                      );

                        case LoginResponseStatus.CorruptedHandshake:
                            throw new VoltConnectionException(
                                      Resources.LRS_CorruptedHandshake
                                      , endPoint
                                      , status
                                      );

                        case LoginResponseStatus.InvalidCredentials:
                            throw new VoltPermissionException(
                                      Resources.LRS_InvalidCredentials
                                      , endPoint
                                      , status
                                      );

                        case LoginResponseStatus.ServerTooBusy:
                            throw new VoltConnectionException(
                                      Resources.LRS_ServerTooBusy
                                      , endPoint
                                      , status
                                      );

                        default:
                            throw new VoltConnectionException(Resources.LRS_Unknown, endPoint, status);
                        }
                    }
                    // Parse the rest of the response the get core cluster information.
                    try
                    {
                        this.ServerHostId          = deserializer.ReadInt32();
                        this.ConnectionId          = deserializer.ReadInt64();
                        this.ClusterStartTimeStamp = deserializer.ReadDateTimeFromMilliseconds();
                        this.LeaderIPEndPoint      = new IPEndPoint(
                            new IPAddress(deserializer.ReadRaw(4))
                            , endPoint.Port
                            );
                        this.BuildString = deserializer.ReadString();
                    }
                    catch (Exception x)
                    {
                        throw new VoltConnectionException(Resources.LR_FailedParsingResponse, x, endPoint);
                    }

                    // Now that we are successfully connected, set the socket timeout to infinite (we are constantly
                    // listening for new messages).
                    this.BaseStream.ResetTimeout(Timeout.Infinite);

                    // Create background threads.
                    this.BackgroundNetworkThread = new Thread(this.BackgroundNetworkThreadRun)
                    {
                        IsBackground = true,
                        Priority     = ThreadPriority.AboveNormal
                    };
                    this.BackgroundTimeoutThread = new Thread(this.BackgroundTimeoutThreadRun)
                    {
                        IsBackground = true
                    };

                    // Starting background processing threads.
                    this.BackgroundNetworkThread.Start();
                    this.BackgroundTimeoutThread.Start();

                    // Start Callback executor
                    this.CallbackExecutor.Start();

                    // Ensure terminal exception is reset
                    this.TerminalException = null;

                    // Connection is now ready.
                    this.Status = ConnectionStatus.Connected;

                    // Initialize statistics as needed.
                    if (this.Settings.StatisticsEnabled)
                    {
                        this.Stats = new Dictionary <string, Statistics>(StringComparer.OrdinalIgnoreCase);
                        // For lifetime statistics, keep track of previous connection cycles, if any.
                        if (this.LifetimeStats != null)
                        {
                            if (this.PastLifetimeStats != null)
                            {
                                this.PastLifetimeStats.SummarizeWith(this.LifetimeStats);
                            }
                            else
                            {
                                this.PastLifetimeStats = this.LifetimeStats;
                            }
                        }
                        this.LifetimeStats = new Statistics();
                    }

                    // Trace as needed
                    if (this.Settings.TraceEnabled)
                    {
                        VoltTrace.TraceEvent(
                            TraceEventType.Information
                            , VoltTraceEventType.ConnectionOpened
                            , Resources.TraceConnectionOpened
                            , this.ServerHostId
                            , this.ConnectionId
                            , endPoint
                            , this.LeaderIPEndPoint
                            , this.ClusterStartTimeStamp
                            , this.BuildString
                            );
                    }
                }
                catch (Exception x)
                {
                    try
                    {
                        // In case of failure, terminate everything immediately (will correct status).
                        this.Terminate();
                    }
                    catch { }
                    // Re-throw exception, wrapping if needed.
                    if (x is VoltException)
                    {
                        throw new VoltConnectionException(Resources.ConnectionFailure, x, endPoint);
                    }
                    else
                    {
                        throw x;
                    }
                }
            }
            return(this);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Terminates the connection and closes all resources.
        /// </summary>
        internal void Terminate()
        {
            // Mark connection as closed
            this.Status = ConnectionStatus.Closed;

            // Stop background threads - swallow any undue exception...
            try
            {
                // Kill the threads, the stream.
                try
                {
                    if (this.OwnsCallbackExecutor)
                    {
                        this.CallbackExecutor.Stop();
                    }
                    this.BackgroundNetworkThread.Abort();
                    this.BackgroundTimeoutThread.Abort();
                    this.BaseStream.Close();
                }
                catch { }

                // Trigger all callbacks on executions we will not be able to fulfill.
                try
                {
                    long[] killList = this.ExecutionCache.GetCurrentItems();
                    while (killList.Length > 0)
                    {
                        foreach (long expiredExecutionId in killList)
                        {
                            // Get the response from the stack
                            Response response = this.ExecutionCache.BeginRemoveItem(expiredExecutionId);

                            // If the response wasn't already dealt with, finalize processing.
                            if (response != null)
                            {
                                // Trigger the callback.  The call is non-blocking: the callback is queued for
                                // execution in the ThreadPool.
                                response.OnExecutionAbort();
                                // Call completion handler for classes that provide additional tracking.
                                this.OnExecutionComplete(
                                    expiredExecutionId
                                    , response.Procedure
                                    , response.ExecutionDuration
                                    , response.Status
                                    , 0                     // Not accurate: the response might come later...
                                    );
                            }
                        }
                        Thread.Sleep(10);
                        killList = this.ExecutionCache.GetCurrentItems();
                    }
                }
                catch { }

                // Freeze statistics so the elapsed time doesn't report nonsensical figures.
                if (this.Settings.StatisticsEnabled)
                {
                    lock ((this.Stats as IDictionary).SyncRoot)
                        foreach (KeyValuePair <string, Statistics> pair in this.Stats)
                        {
                            pair.Value.Freeze();
                        }
                    this.LifetimeStats.Freeze();
                }

                // Trace as needed.
                if (this.Settings.TraceEnabled)
                {
                    VoltTrace.TraceEvent(
                        TraceEventType.Information
                        , VoltTraceEventType.ConnectionClosed
                        , Resources.TraceConnectionClosed
                        , this.ServerHostId
                        , this.ConnectionId
                        );
                }
            }
            catch { }
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Asynchronously execute a procedure against a VoltDB database, returning immediately to the calling thread.
        /// The provided callback will be fired upon completion.
        /// </summary>
        /// <typeparam name="T">Data type of the expected response result for the call (Table[], Table,
        /// SingleRowTable[], SingleRowTable, T[][], T[] or T, with T one of the supported value types).</typeparam>
        /// <param name="callback">The callback method to call upon completion.</param>
        /// <param name="state">A user-defined state object to be passed to your callback through the Response's
        /// .AsyncState property</param>
        /// <param name="timeout">Timeout value (overrides connection settings DefaultCommandTimeout). Use
        /// Timeout.Infinite or -1 for infinite timeout.</param>
        /// <param name="procedure">The name of the procedure to call.</param>
        /// <param name="procedureUtf8">The UTF-8 bytes of the procedure name.</param>
        /// <param name="parameters">List of parameters to pass to the procedure.</param>
        /// <returns>The execution handle for the request.</returns>
        public override AsyncResponse <T> BeginExecute <T>(
            ExecuteAsyncCallback <T> callback
            , object state
            , int timeout
            , string procedure
            , byte[] procedureUtf8
            , params object[] parameters
            )
        {
            // Correct default timeout usage.
            if (timeout == 0)
            {
                timeout = this.Settings_DefaultCommandTimeout;
            }
            else if (timeout < -1)
            {
                throw new ArgumentOutOfRangeException(string.Format(Resources.InvalidTimeoutValue, timeout));
            }

            // Validate connection status.
            if (this.Status != ConnectionStatus.Connected)
            {
                if (this.TerminalException != null)
                {
                    throw this.TerminalException;
                }
                else
                {
                    throw new InvalidOperationException(string.Format(Resources.InvalidConnectionStatus, this.Status));
                }
            }

            // Assign execution id.
            long executionId = Interlocked.Increment(ref this.ExecutionId);

            // Prepare the response object.
            AsyncResponse <T> response = new AsyncResponse <T>(this, executionId, timeout, callback, state, procedure, parameters);

            // Attempt asynchronouse execution - any failure will trigger a synchronous failure.
            try
            {
                // This might fail (invalid parameters / exceeding max string length, for instance) - the equivalent of an
                // ArgumentException, so we leave it outside of the try/catch block related to protecting ourselves against
                // connectivity issues.
                var message = GetProcedureCallMessage(executionId, procedureUtf8, parameters);

                // Block if we reached queue capacity.
                while (this.ExecutionCache.Size >= this.Settings_MaxOutstandingTxns)
                {
                    Thread.Sleep(1);
                }

                // The request appears to be properly formatted and ready to ship - push it in the queue.
                this.ExecutionCache.AddItem(response);

                // Write out execution request to protocol stream - lock out access for thread safety around the underlying
                // stream.
                lock (this.SyncRoot)
                {
                    try
                    {
                        this.BaseStream.WriteMessage(message.Array, message.Offset, message.Count);
                    }
                    catch (Exception x)
                    {
                        // We will only get here in case of a network/connection failure.

                        // Swallow any exception: the background processing thread will pick up a network failure as well
                        // and we will let it initiate termination and kick out the abort on the request just posted.

                        // We still set the Terminal exception so we report the *first* exception encountered (failing to
                        // write on the stream here, in case the background thread picks things up first, failing to read).
                        this.TerminalException = new VoltExecutionException(Resources.ConnectionClosedDuringAWrite, x);

                        // But, as stated, we do not re-throw: connection termination will ensure that all pending requests
                        // are rejected with an "abort" exception.  The next execution call will fail directly on a
                        // "connection closed" error, or be blocked until recovery is complete.
                    }
                }

                // Track statistics as needed.
                TrackStatisticsOpenRequest(procedure, message.Count);

                // Trace as needed.
                if (this.Settings_TraceEnabled)
                {
                    VoltTrace.TraceEvent(
                        TraceEventType.Information
                        , VoltTraceEventType.ExecutionStarted
                        , Resources.TraceExecutionStarted
                        , this.ServerHostId
                        , this.ConnectionId
                        , executionId
                        , procedure
                        );
                }
            }
            catch (Exception x)
            {
                response.OnExecutionRequestFailed(new VoltExecutionException(Resources.RequestExecutionFailure, x));
            }
            // Return execution handle to caller.
            return(response);
        }