Beispiel #1
0
        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;
        }
Beispiel #2
0
        internal async Task RunBatchAsync(TableBatchOperation batch)
        {
            TableBatchOperation batchCopy    = ChainTableUtils.CopyBatch <DynamicTableEntity>(batch);
            TableCall           originalCall = async table => await table.ExecuteBatchAsync(batch);

            MirrorTableCall referenceCall = async referenceTable => await referenceTable.ExecuteMirrorBatchAsync(batchCopy, successfulBatchResult);

            Console.WriteLine("{0} starting batch: {1}", machineId, BetterComparer.ToString(batch));
            await RunCallAsync(originalCall, referenceCall);
        }
Beispiel #3
0
            public Task <TElement> ReadRowAsync()
            {
                if (continuationKey == null)
                {
                    return(Task.FromResult(default(TElement)));
                }
                List <DynamicTableEntity> possibleRows = outer.GetValidStreamReadRows(startRevision, filterExpr, continuationKey);
                int choiceIndex           = PSharpNondeterminism.Choice(possibleRows.Count);
                DynamicTableEntity choice = possibleRows[choiceIndex];

                Console.WriteLine("NondeterministicQueryStream: possibleRows {0}, choiceIndex {1}",
                                  BetterComparer.ToString(possibleRows), choiceIndex);
                continuationKey = (choice == null) ? null : ChainTableUtils.NextValidPrimaryKeyAfter(choice.GetPrimaryKey());
                return(Task.FromResult((choice == null) ? default(TElement) : ChainTableUtils.CopyEntity <TElement>(choice)));
            }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        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);
        }
Beispiel #6
0
        // 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;
        }