private void TestModeSerialize(ActionStateBase state) { if (this.isTestMode) { // DEBUG///////////////////////////////////////////// TestabilityTrace.TraceSource.WriteInfo(TraceType, "Begin test"); try { byte[] bytes = state.ToBytes(); ActionStateBase deserializedData = this.ReadData(bytes); if (!state.VerifyEquals(deserializedData)) { ReleaseAssert.Failfast("{0} data should match but does not", state.OperationId); } } catch (Exception e) { TestabilityTrace.TraceSource.WriteError(TraceType, "{0} - TestModeSerialize exception {1}", state.OperationId.ToString(), e.ToString()); throw; } } }
// "throwException" - if this call originated from a client call, the exception should be thrown back. private async Task PersistAsync(ActionStateBase actionState, bool throwException) { StepStateNames currentStateName = actionState.StateProgress.Peek(); byte[] stateToPersist = actionState.ToBytes(); try { using (var tx = this.stateManager.CreateTransaction()) { TestabilityTrace.TraceSource.WriteInfo(TraceType, "Enter transaction inside {0} - operationId={1}", "PersistAsync", actionState.OperationId); if (actionState.StateProgress.Peek() == StepStateNames.CompletedSuccessfully || actionState.StateProgress.Peek() == StepStateNames.Failed) { await this.actionTable.TryRemoveAsync(tx, actionState.OperationId, DefaultDictionaryTimeout, this.cancellationToken).ConfigureAwait(false); TestabilityTrace.TraceSource.WriteInfo( TraceType, "Adding {0} to history table state={1}, rollbackState={2}", actionState.OperationId, actionState.StateProgress.Peek(), actionState.RollbackState.ToString()); await this.historyTable.AddOrUpdateAsync(tx, actionState.OperationId, stateToPersist, (k, v) => stateToPersist, DefaultDictionaryTimeout, this.cancellationToken).ConfigureAwait(false); } else { await this.actionTable.AddOrUpdateAsync(tx, actionState.OperationId, stateToPersist, (k, v) => stateToPersist, DefaultDictionaryTimeout, this.cancellationToken).ConfigureAwait(false); } await tx.CommitAsync().ConfigureAwait(false); } try { if (actionState.StateProgress.Peek() == StepStateNames.CompletedSuccessfully) { await actionState.AfterSuccessfulCompletion().ConfigureAwait(false); } else if (actionState.StateProgress.Peek() == StepStateNames.Failed) { await actionState.AfterFatalRollback().ConfigureAwait(false); } } catch (Exception ex) { TestabilityTrace.TraceSource.WriteInfo(TraceType, "{0} afterX threw {1}, reporting fault", actionState.OperationId, ex); this.partition.ReportFault(FaultType.Transient); } TestabilityTrace.TraceSource.WriteInfo(TraceType, "Enter transaction inside {0} - operationId={1}", "PersistAsync", actionState.OperationId); } catch (Exception e) { TestabilityTrace.TraceSource.WriteInfo(TraceType, "Error in persisting in state " + currentStateName + " " + e.ToString()); throw; } if (this.isTestMode) { this.TestModeSerialize(actionState); } TestabilityTrace.TraceSource.WriteInfo(TraceType, "{0} Exiting PersistAsync", actionState.OperationId); }
public async Task CancelTestCommandAsync(Guid operationId, bool force) { ActionStateBase state = null; try { using (var tx = this.stateManager.CreateTransaction()) { TestabilityTrace.TraceSource.WriteInfo(TraceType, "Enter transaction inside {0} - operationId={1}", "CancelTestCommandAsync", operationId); var data = await this.actionTable.TryGetValueAsync(tx, operationId, DefaultDictionaryTimeout, this.cancellationToken).ConfigureAwait(false); if (data.HasValue) { state = this.ReadData(data.Value); } else { string error = string.Format(CultureInfo.InvariantCulture, "OperationId '{0}' was not found", operationId); TestabilityTrace.TraceSource.WriteWarning(TraceType, error); throw FaultAnalysisServiceUtility.CreateException(TraceType, Interop.NativeTypes.FABRIC_ERROR_CODE.FABRIC_E_KEY_NOT_FOUND, error); } TestabilityTrace.TraceSource.WriteInfo(TraceType, "CancelActionAsync: operationId={0}, force={1}", operationId, force); if (force) { if (state.RollbackState != RollbackState.RollingBackDueToUserCancel) { string error = string.Format(CultureInfo.InvariantCulture, "CancelActionAsync: operationId={0}, force is not allowed for something in {1}", operationId, state.RollbackState.ToString()); TestabilityTrace.TraceSource.WriteError(TraceType, error); throw FaultAnalysisServiceUtility.CreateException(TraceType, Interop.NativeTypes.FABRIC_ERROR_CODE.FABRIC_E_INVALID_TEST_COMMAND_STATE, error); } else { state.RollbackState = RollbackState.RollingBackForce; } } else { // if it's in force, don't allow it back down to graceful if (state.RollbackState == RollbackState.RollingBackForce) { string error = string.Format( CultureInfo.InvariantCulture, "CancelActionAsync: operationId={0}, CancelTestCommandAsync has already been called with force==true. Switching to force==false is not valid.", operationId); TestabilityTrace.TraceSource.WriteWarning(TraceType, error); throw FaultAnalysisServiceUtility.CreateException(TraceType, Interop.NativeTypes.FABRIC_ERROR_CODE.FABRIC_E_INVALID_TEST_COMMAND_STATE, error); } state.RollbackState = RollbackState.RollingBackDueToUserCancel; } byte[] stateToPersist = state.ToBytes(); await this.actionTable.AddOrUpdateAsync(tx, state.OperationId, stateToPersist, (k, v) => stateToPersist, DefaultDictionaryTimeout, this.cancellationToken).ConfigureAwait(false); await tx.CommitAsync().ConfigureAwait(false); TestabilityTrace.TraceSource.WriteInfo(TraceType, "CancelActionAsync: operationId={0}, force={1} committed", operationId, force); } TestabilityTrace.TraceSource.WriteInfo(TraceType, "Enter transaction inside {0} - operationId={1}", "CancelTestCommandAsync", operationId); } catch (FabricNotPrimaryException fnp) { FaultAnalysisServiceUtility.TraceFabricNotPrimary(operationId, fnp); throw; } catch (Exception e) { TestabilityTrace.TraceSource.WriteError(TraceType, "CancelActionAsync: {0}", e.ToString()); throw; } }