Exemplo n.º 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;
        }
Exemplo n.º 2
0
        internal async Task RunQueryAtomicAsync(TableQuery <DynamicTableEntity> query)
        {
            // async/await pair needed to upcast the return value to object.
            TableCall originalCall = async table => await table.ExecuteQueryAtomicAsync(query);

            MirrorTableCall referenceCall = async referenceTable => await referenceTable.ExecuteQueryAtomicAsync(query);

            Console.WriteLine("{0} starting atomic query: {1}", machineId, query);
            await RunCallAsync(originalCall, referenceCall);
        }
Exemplo n.º 3
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);
        }
Exemplo n.º 4
0
        // These two should do the same thing.  Which do we prefer?

        /*
         * Task<object> ITablesMachineAnnotation.AnnotateLastOutgoingCallAsync(MirrorTableCall referenceCall)
         * {
         *  if (referenceCall == null)
         *      return Task.FromResult((object)null);
         *  return referenceCall(referenceTable);
         * }
         */
        async Task <object> ITablesMachineAnnotation.AnnotateLastBackendCallAsync(
            MirrorTableCall referenceCall, IList <SpuriousETagChange> spuriousETagChanges)
        {
            if (spuriousETagChanges == null)
            {
                spuriousETagChanges = new List <SpuriousETagChange>();
            }

            if (referenceCall == null)
            {
                if (spuriousETagChanges.Count > 0)
                {
                    var batch            = new TableBatchOperation();
                    var originalResponse = new List <TableResult>();
                    foreach (SpuriousETagChange change in spuriousETagChanges)
                    {
                        batch.Merge(new DynamicTableEntity
                        {
                            PartitionKey = change.partitionKey,
                            RowKey       = change.rowKey,
                            ETag         = ChainTable2Constants.ETAG_ANY
                        });
                        originalResponse.Add(new TableResult {
                            Etag = change.newETag
                        });
                    }
                    try
                    {
                        await referenceTable.ExecuteMirrorBatchAsync(batch, originalResponse, null, null);
                    }
                    catch (StorageException ex)
                    {
                        // Make sure this doesn't get swallowed by a generic StorageException catch block.
                        throw new InvalidOperationException("Invalid spurious ETag change annotation.", ex);
                    }
                }
                return(null);
            }
            else
            {
                if (spuriousETagChanges.Count > 0)
                {
                    throw new ArgumentException("spuriousETagChanges currently not allowed with a reference call");
                }
                return(await referenceCall(referenceTable));
            }
        }
Exemplo n.º 5
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;
        }