/// <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;
            }
        }