/// <summary>
        /// Wait for completion of the request and return the result (or throw an exception if there was a failure).
        /// </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="asyncResponse">The execution handle for the request</param>
        /// <returns>The request's response</returns>
        internal static AsyncResponse <T> EndExecute <T>(AsyncResponse <T> asyncResponse)
        {
            // Wait until completion (Note: timeout control is already managed by the background thread, so we do not
            // specify a(nother!) timeout on the WaitHandle).
            if (!asyncResponse.IsCompleted)
            {
                asyncResponse.AsyncWaitHandle.WaitOne();
            }

            // If there was an error, throw it right out.
            if (asyncResponse.Status != ResponseStatus.Success)
            {
                throw asyncResponse.Exception;
            }

            // Return the response.
            return(asyncResponse);
        }
Пример #2
0
 /// <summary>
 /// Cancels the request associated to this execution, causing triggerring of the Asynchronous callback with a
 /// VoltClientAbortException result.  Understand that this process merely lets you decide to "forget" about
 /// the request, however, the execution has been posted to the server and will be completed all the same.
 /// </summary>
 /// <param name="asyncResponse">The execution handle for the request</param>
 private void ExecuteCancelAsync(AsyncResponse <TResult> asyncResponse)
 {
     asyncResponse.Cancel();
 }
Пример #3
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);
        }