internal override async Task HandleLinearizationPoint(IList <TableResult> successfulBatchResult) { PSharpRuntime.Assert(currentReferenceOutcome == null, "The call already reported a linearization point."); this.successfulBatchResult = successfulBatchResult; currentReferenceOutcome = await Catching <StorageException> .Task( annotationProxy.AnnotateLastBackendCallAsync(currentReferenceCall, null)); }
async Task RunCallAsync(TableCall originalCall, MirrorTableCall referenceCall) { // TODO: All assertions should show what the call was. // XXX: We currently have no way to detect incorrect interleaving of // backend calls and AnnotateLastOutgoingCall here. Most incorrect // interleavings will cause an error on the TablesMachine, but some // may go undetected. // For now, we're not doing streaming queries at all, so we don't have // to worry about how to handle them. currentReferenceCall = referenceCall; object actualOutcome = await Catching <StorageException> .Task(originalCall(migratingTable)); // Verify that successfulBatchResult was correct if specified. // (Ideally, we'd also catch if it isn't specified when it should // be, but that's less of a risk as it will likely cause ETag // mismatches anyway.) if (successfulBatchResult != null) { var successfulBatchOutcome = new Outcome <object, StorageException>(successfulBatchResult); PSharpRuntime.Assert(BetterComparer.Instance.Equals(successfulBatchOutcome, actualOutcome), "{0} incorrect successfulBatchResult:\n{1}\nExpected:\n{2}\n", machineId, BetterComparer.ToString(successfulBatchOutcome), BetterComparer.ToString(actualOutcome)); } PSharpRuntime.Assert(currentReferenceOutcome != null, "The call completed without reporting a linearization point."); PSharpRuntime.Assert(BetterComparer.Instance.Equals(actualOutcome, currentReferenceOutcome), "{0} call outcome:\n{1}\nExpected:\n{2}\n", machineId, BetterComparer.ToString(actualOutcome), BetterComparer.ToString(currentReferenceOutcome)); // Reset fields currentReferenceCall = null; successfulBatchResult = null; currentReferenceOutcome = null; }
public async void Dispatch() { Outcome <TResult, Exception> outcome; string argsDebug = string.Join(",", from a in args select BetterComparer.ToString(a)); Console.WriteLine(string.Format("Start call from {0} to {1}: {2}.{3}({4})", realProxy.callerMachineId, realProxy.hostMachineId, realProxy.targetDebugName, method.Name, argsDebug)); object obj; try { obj = method.Invoke(realProxy.target, args); } catch (TargetInvocationException e) { outcome = new Outcome <TResult, Exception>(e.InnerException); goto Finish; } Task <TResult> task = obj as Task <TResult>; if (task == null) { // The more obvious task = ((Task)obj).ContinueWith(_ => default(TResult)) // executes outside the synchronization context and posts a continuation // back to the synchronization context, which calls Send, which trips my // assertion in the P# scheduler. task = ((Func <Task <TResult> >)(async() => { await(Task) obj; return(default(TResult)); }))(); } outcome = await Catching <Exception> .Task(task); Finish: Console.WriteLine(string.Format("End call from {0} to {1}: {2}.{3}({4}) with outcome: {5}", realProxy.callerMachineId, realProxy.hostMachineId, realProxy.targetDebugName, method.Name, argsDebug, BetterComparer.ToString(outcome))); replyTarget.SetOutcome(outcome); }
// This method does not log what the call is, since there's no way to // know what's inside the delegates. Use RunBatchAsync or RunQueryAtomicAsync. async Task RunCallAsync(TableCall originalCall, MirrorTableCall referenceCall) { // TODO: All assertions should show what the call was. // XXX: We currently have no way to detect incorrect interleaving of // backend calls and AnnotateLastOutgoingCall here. Most incorrect // interleavings will cause an error on the TablesMachine, but some // may go undetected. // - FIXME: A missing annotation will cause all machines to become blocked, and // P# considers that a success! To fix that, we need to enable liveness checking. currentReferenceCall = referenceCall; object actualOutcome = await Catching <StorageException> .RunAsync(() => originalCall(migratingTable)); // Verify that successfulBatchResult was correct if specified. // (Ideally, we'd also catch if it isn't specified when it should // be, but that's less of a risk as it will likely cause ETag // mismatches anyway.) if (successfulBatchResult != null) { var successfulBatchOutcome = new Outcome <object, StorageException>(successfulBatchResult); PSharpRuntime.Assert(BetterComparer.Instance.Equals(successfulBatchOutcome, actualOutcome), "{0} incorrect successfulBatchResult:\n{1}\nExpected:\n{2}\n", machineId, BetterComparer.ToString(successfulBatchOutcome), BetterComparer.ToString(actualOutcome)); } PSharpRuntime.Assert(currentReferenceOutcome != null, "{0}: The call completed without reporting a linearization point.", machineId); PSharpRuntime.Assert(BetterComparer.Instance.Equals(actualOutcome, currentReferenceOutcome), "{0} table call outcome is incorrect:\n{1}\nExpected:\n{2}\n", machineId, BetterComparer.ToString(actualOutcome), BetterComparer.ToString(currentReferenceOutcome)); Console.WriteLine("{0} table call outcome is correct:\n{1}", machineId, BetterComparer.ToString(actualOutcome)); // Reset fields currentReferenceCall = null; successfulBatchResult = null; currentReferenceOutcome = null; }