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; }
void DispatchTableCall() { numTableCalls++; // Crude liveness check, since a monitor did not work (see below). PSharpRuntime.Assert(numTableCalls <= MigrationModel.TABLE_CALL_LIMIT, "A service machine may be in an infinite loop."); DispatchPayload(); }
internal async Task RunQueryStreamedAsync(TableQuery <DynamicTableEntity> query) { int startRevision = await peekProxy.GetReferenceTableRevisionAsync(); FilterExpression filterExpr = ChainTableUtils.ParseFilterString(query.FilterString); Console.WriteLine("{0} starting streaming query: {1}", machineId, query); using (IQueryStream <DynamicTableEntity> stream = await migratingTable.ExecuteQueryStreamedAsync(query)) { PrimaryKey lastKey = ChainTableUtils.FirstValidPrimaryKey; for (;;) { PrimaryKey returnedContinuationKey = await stream.GetContinuationPrimaryKeyAsync(); PSharpRuntime.Assert(returnedContinuationKey == null || returnedContinuationKey.CompareTo(lastKey) >= 0, "{0}: query stream continuation key is {1}, expected >= {2}", machineId, returnedContinuationKey, lastKey); DynamicTableEntity row = await stream.ReadRowAsync(); // may be null, meaning end of stream // Must be after ReadRowAsync, otherwise additional rows could become valid // due to a mutation between GetValidStreamReadRows and ReadRowAsync and // we would falsely report a bug if ReadRowAsync returns one of those rows. List <DynamicTableEntity> validRows = await peekProxy.GetValidStreamReadRows(startRevision, filterExpr, lastKey); // Three cheers for automatic use of covariance in overload resolution! PSharpRuntime.Assert(validRows.Contains(row, BetterComparer.Instance), "{0} query stream returned {1}, which is not one of the valid rows: {2}", machineId, BetterComparer.ToString(row), BetterComparer.ToString(validRows)); Console.WriteLine("{0} query stream returned row {1}, which is valid", machineId, BetterComparer.ToString(row)); if (row == null) { // Any returnedContinuationKey (including null) is less or equal to a row of null. break; } else { PSharpRuntime.Assert(returnedContinuationKey != null && returnedContinuationKey.CompareTo(row.GetPrimaryKey()) <= 0, "{0}: query stream continuation key is {1}, expected <= {2}", machineId, returnedContinuationKey, row.GetPrimaryKey()); lastKey = ChainTableUtils.NextValidPrimaryKeyAfter(row.GetPrimaryKey()); } } } Console.WriteLine("{0} finished streaming query", machineId); }
// 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; }
async Task DoQueryStreamed() { int startRevision = await peekProxy.GetReferenceTableRevisionAsync(); // XXX: Test the filtering? var query = new TableQuery <DynamicTableEntity>(); using (IQueryStream <DynamicTableEntity> stream = await migratingTable.ExecuteQueryStreamedAsync(query)) { PrimaryKey continuationKey = await stream.GetContinuationPrimaryKeyAsync(); await peekProxy.ValidateQueryStreamGapAsync(startRevision, null, continuationKey); do { DynamicTableEntity row = await stream.ReadRowAsync(); PrimaryKey newContinuationKey = await stream.GetContinuationPrimaryKeyAsync(); if (row == null) { PSharpRuntime.Assert(newContinuationKey == null); await peekProxy.ValidateQueryStreamGapAsync(startRevision, continuationKey, null); } else { await peekProxy.ValidateQueryStreamGapAsync(startRevision, continuationKey, row.GetPrimaryKey()); await peekProxy.ValidateQueryStreamRowAsync(startRevision, row); await peekProxy.ValidateQueryStreamGapAsync(startRevision, ChainTableUtils.NextValidPrimaryKeyAfter(row.GetPrimaryKey()), newContinuationKey); } continuationKey = newContinuationKey; } while (continuationKey != null); } }
/// <summary> /// Registers the testing runtime. /// </summary> /// <param name="runtime">The testing runtime.</param> public void RegisterRuntime(PSharpRuntime runtime) { runtime.Assert((runtime as TestingRuntime) != null, "Requires passed runtime to support method GetCurrentMachineId"); this.Runtime = runtime as TestingRuntime; }
public void SetRuntime(PSharpRuntime runtime) { runtime.Assert((runtime as BugFindingRuntime) != null, "Requires passed runtime to support method GetCurrentMachineId"); this.Runtime = runtime as BugFindingRuntime; }