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