예제 #1
0
        /// <summary>
        /// Parallel task that checks if the transaction has been aborted internally
        /// If so, cause the waiting dequeuer to throw InvalidOperationException
        /// </summary>
        private async Task PollTransactionStateAsync(
            Transaction txn,
            TaskCompletionSource <ConditionalValue <IListElement <T> > > tcs,
            CancellationToken cancellationToken)
        {
            while (true)
            {
                // Ignore the exception thrown by this call
                // As this polls every 4 secs, The cancellationTokenSource could have been disposed and set to null
                //    causing Task.Delay to throw ObjectDisposedException.
                // The token would be honoured by the StartTimerAsync task and the tcs would be set to the TaskCanceledException.
                await Task.Delay(this.DefaultTransactionStatePollingTimeout, cancellationToken).ConfigureAwait(false);

                if (tcs.Task.IsCompleted)
                {
                    // If the tcs was already set, no need to wait check the transaction state.
                    // End transaction polling task
                    return;
                }

                switch (txn.State)
                {
                case TransactionState.Active:
                case TransactionState.Reading:
                    // Do nothing, the transaction is still active, go back to sleep
                    break;

                case TransactionState.Aborted:
                case TransactionState.Aborting:
                case TransactionState.Faulted:
                    tcs.TrySetException(
                        new InvalidOperationException(
                            string.Format("DataStore.PollTransactionStateAsync : The transaction was aborted or faulted, dispose the transaction and try again, Txn : {0}", txn)));
                    return;

                case TransactionState.Committed:
                case TransactionState.Committing:
                    var exc =
                        new InvalidOperationException(
                            string.Format(
                                "DataStore.PollTransactionStateAsync : The transaction was commited but DequeueAsync did not finish. Make sure DequeueAsync was awaited. Txn : {0}",
                                txn));

                    if (tcs.TrySetException(exc))
                    {
                        // If we were able to set the result, then DequeueAsync was not awaited.
                        // Do not Assert as this is something that the user is doing incorrectly.
                        // Do not throw as the exception would be thrown by the tcs.
                        FabricEvents.Events.ReliableConcurrentQueue_ExceptionWarning(this.traceType, exc.ToString());
                    }

                    return;

                default:
                    // Unknown transaction state : Assert
                    TestableAssertHelper.FailInvalidOperation(this.traceType, "DataStore.PollTransactionStateAsync", "Unknown transaction state");
                    return;
                }
            }
        }
예제 #2
0
 /// <summary>
 /// The prepare for remove async.
 /// </summary>
 /// <param name="transaction">
 /// The transaction.
 /// </param>
 /// <param name="timeout">
 /// The timeout.
 /// </param>
 /// <param name="cancellationToken">
 /// The cancellation token.
 /// </param>
 /// <returns>
 /// The <see cref="Task"/>.
 /// </returns>
 Task IStateProvider2.PrepareForRemoveAsync(
     Transaction transaction,
     TimeSpan timeout,
     CancellationToken cancellationToken)
 {
     Trace.TraceInformation("[" + this.partitionId + "] " + "PrepareForRemoveAsync()");
     return(Task.FromResult(0));
 }
예제 #3
0
        /// <summary>
        /// Try and dequeue from the DataStore.
        /// If there are dequeuers waiting or there is no element to dequeue, this dequeueur would be added to the waiting queue.
        /// Else, the result would be set for the <paramref name="tcs"/>
        /// Caller must await on tcs.Task
        /// </summary>
        public void TryDequeue(
            Transaction txn,
            TaskCompletionSource <ConditionalValue <IListElement <T> > > tcs,
            TimeSpan timeout,
            CancellationToken cancellationToken)
        {
            lock (this.updateLatch)
            {
                switch (this.dequeuersState)
                {
                case DequeuerState.Aborting:
                case DequeuerState.Closing:
                    tcs.TrySetException(
                        new FabricObjectClosedException(
                            string.Format("Queue is closed. Please dispose the current transaction and retry the operation with a new transaction, Cause : {0}", this.dequeuersState)));
                    return;

                case DequeuerState.None:
                case DequeuerState.ChangeRoleFromPrimary:
                    tcs.TrySetException(
                        new FabricNotPrimaryException(
                            string.Format("Current role not Primary. Please dispose the current transaction and retry the operation with a new transaction, Cause : {0}", this.dequeuersState)));
                    return;

                case DequeuerState.OnPrimary:
                    // In the expected state, continue DataStore.TryDequeue
                    break;

                default:
                    TestableAssertHelper.FailInvalidOperation(
                        this.traceType,
                        "TryDequeue",
                        "DataStore.TryDequeue : Trying to add a dequeuer in an invalid state. Current DequeuerState = {0}",
                        this.dequeuersState);
                    break;     // unreachable
                }

                var res = this.TryUnlinkHead();

                if (res.HasValue)
                {
                    // There is something to unlink and no waiting dequeuer
                    if (!tcs.TrySetResult(res))
                    {
                        TestableAssertHelper.FailInvalidOperation(
                            this.traceType,
                            "TryDequeue",
                            "Could not set the tcs result after unlinking from the DataStore. TCS {0}",
                            res);
                    }
                }
                else
                {
                    this.AddDequeuer(txn, tcs, timeout, cancellationToken);
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Start a timer and add the <paramref name="tcs"/> to the dequeuerQueue
        /// Should be called under the updateLatch
        /// </summary>
        private void AddDequeuer(
            Transaction txn,
            TaskCompletionSource <ConditionalValue <IListElement <T> > > tcs,
            TimeSpan timeSpan,
            CancellationToken cancellationToken)
        {
            this.dequeuerQueue.Enqueue(tcs);

            // Fire the timer task
            var t1 = this.StartDequeueTimerAsync(tcs, timeSpan, cancellationToken);
            var t2 = this.PollTransactionStateAsync(txn, tcs, cancellationToken).IgnoreException();
        }