/// <summary>
        /// Adds an operation to the state of the atomic redo operation, that is immediately committed.
        /// One atomic redo operation can contain only 1 operation:- and hence the name.
        /// Atomic redo operations cannot be 'committed' or 'rolled' back explicitly.
        /// </summary>
        /// <param name="metaData">metadata bytes pertaining to the operation.</param>
        /// <param name="redo">Byte stream that contains the 'redo' data when this atomic redo operation is to be committed and the effects of this operation are to be applied</param>
        /// <param name="operationContext"> A user defined context</param>
        /// <param name="stateProviderId">Id of the state provider</param>
        /// <exception cref="FabricNotPrimaryException">
        /// If replica role is not primary
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If Transaction is not active (Already committed or aborted)
        /// </exception>
        public async Task AddOperationAsync(
            OperationData metaData,
            OperationData redo,
            object operationContext,
            long stateProviderId)
        {
            // Can throw InvalidOperationException.
            // Note that this check protects against an Assert in SM that checks that Apply is only called with transactions that have
            // isPrimaryTransaction set to true.
            this.ThrowIfNotPrimaryTransaction();
            this.ThrowIfNotPrimary();

            StateMachine.OnBeginAtomicOperationAddAsync();

            try
            {
                await TransactionalReplicator.AddOperationAsync(this, metaData, redo, operationContext, stateProviderId).ConfigureAwait(false);

                StateMachine.OnAtomicOperationSuccess();
            }
            catch (Exception e)
            {
                var isRetryable = ProcessException(e);

                // If this is a retryable exception, set the this.TransactionalReplicator so that the operation can be retried by the user
                if (isRetryable == true)
                {
                    StateMachine.OnAtomicOperationRetry();
                    throw;
                }

                StateMachine.OnAtomicOperationFaulted();
                throw;
            }
        }
 /// <summary>
 /// Initializes a new instance of the StatefulServiceReplica class.
 /// </summary>
 protected StatefulServiceReplica()
 {
     this.transactionalReplicator = new TransactionalReplicator(this.OnDataLossAsync)
     {
         StateProviderFactory = this.CreateStateProvider
     };
 }
示例#3
0
        private async Task PrivateCommitAsync()
        {
            // MCoskun: Note that was TransactionState has moved to Committing it cannot go back to Active.
            // If this invariant changes, releasing read locks here will cause 2PL to be broken.
            this.ReleaseReadLocks();

            if ((this.IsAtomicOperation == false) && (this.IsWriteTransaction == true))
            {
                this.CommitLatencyWatch.Start();

                do
                {
                    try
                    {
                        if (this.firstOperation != null)
                        {
                            // Commit is invoked after only 1 operation in the transaction.
                            // Convert this to a single operation transaction and avoid replicating a commit record
                            await TransactionalReplicator.BeginTransactionAsync(
                                this,
                                this.firstOperation.MetaData,
                                this.firstOperation.Undo,
                                this.firstOperation.Redo,
                                this.firstOperation.Context,
                                this.firstOperation.StateProviderId).ConfigureAwait(false);
                        }
                        else
                        {
                            await TransactionalReplicator.CommitTransactionAsync(this).ConfigureAwait(false);
                        }

                        StateMachine.OnCommitSuccessful();
                        return;
                    }
                    catch (Exception e)
                    {
                        var isRetryable = ProcessException(e);
                        if (isRetryable == false)
                        {
                            StateMachine.OnCommitFaulted();
                            this.ThrowReplicationException(e, false);
                        }
                    }

                    this.TransactionRetryDelay *= RetryBackoffFactor;
                    if (this.TransactionRetryDelay > MaxRetryDelay)
                    {
                        this.TransactionRetryDelay = MaxRetryDelay;
                    }

                    await Task.Delay(this.TransactionRetryDelay).ConfigureAwait(false);
                } while (true);
            }

            // A readonly transaction or atomic operation is considered committed
            StateMachine.OnCommitSuccessful();
        }
示例#4
0
        private async Task <long> AbortTransactionAsync()
        {
            Utility.Assert(
                (this.IsAtomicOperation == false) && (this.IsWriteTransaction == true),
                "(this.IsAtomicOperation ({0}) == false) && (this.IsWriteTransaction( {1}) == true)",
                this.IsAtomicOperation, this.IsWriteTransaction);

            // Optimization: If the first operation is not yet replicated and this transaction is aborted we need to replicate the abort.
            // Hence just drop the cached first operation and return to user
            if (this.firstOperation != null)
            {
                if (this.firstOperation.Context != null)
                {
                    try
                    {
                        TransactionalReplicator.SingleOperationTransactionAbortUnlock(this.firstOperation.StateProviderId, this.firstOperation.Context);
                    }
                    catch (Exception e)
                    {
                        Utility.Assert(false, "DynamicStateManager.SingleOperationTransactionAbortUnlock is not expected to throw any exception. Exception {0}:{1}", e.Message, e.StackTrace);
                    }
                }

                this.firstOperation = null;
                StateMachine.OnAbortSuccessful();
                return(LogicalSequenceNumber.InvalidLsn.LSN);
            }

            do
            {
                try
                {
                    var lsn = await TransactionalReplicator.AbortTransactionAsync(this).ConfigureAwait(false);

                    StateMachine.OnAbortSuccessful();
                    return(lsn);
                }
                catch (Exception e)
                {
                    var isRetryable = ProcessException(e);
                    if (isRetryable == false)
                    {
                        StateMachine.OnAbortFaulted();
                        throw;
                    }
                }

                this.TransactionRetryDelay *= RetryBackoffFactor;
                if (this.TransactionRetryDelay > MaxRetryDelay)
                {
                    this.TransactionRetryDelay = MaxRetryDelay;
                }

                await Task.Delay(this.TransactionRetryDelay).ConfigureAwait(false);
            } while (true);
        }
示例#5
0
        private async Task <long> PrivateGetVisibilitySequenceNumberAsync()
        {
            // Opportunistic check.
            if (this.visibilitySequenceNumber == LogicalSequenceNumber.InvalidLsn.LSN)
            {
                this.visibilitySequenceNumber = await TransactionalReplicator.RegisterAsync().ConfigureAwait(false);
            }

            return(this.visibilitySequenceNumber);
        }