/// <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 }; }
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(); }
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); }
private async Task <long> PrivateGetVisibilitySequenceNumberAsync() { // Opportunistic check. if (this.visibilitySequenceNumber == LogicalSequenceNumber.InvalidLsn.LSN) { this.visibilitySequenceNumber = await TransactionalReplicator.RegisterAsync().ConfigureAwait(false); } return(this.visibilitySequenceNumber); }