private static void CheckResults()

in ironclad-apps/tools/NuBuild/ItemCacheTool/Program.cs [408:580]


        private static void CheckResults(
            IItemCache[] queriedCaches,
            bool cleanup)
        {
            // We can do this for Local, Cloud, or both.
            foreach (IItemCache cache in queriedCaches)
            {
                // We have one Objects container for objects referenced by
                // results in both the Results and FailedResults containers.
                HashSet<string> objects = cache.GetItemsInContainer(ItemCacheContainer.Objects);

                // Likewise, we have only one Sources container.
                // REVIEW: Should a "source" ever show up as a verb result?
                HashSet<string> sources = cache.GetItemsInContainer(ItemCacheContainer.Sources);

                // We initialize the orphanedObjects set to all objects and
                // then remove objects from the set when we find them listed
                // in a result (stored in either Results or FailedResults).
                HashSet<string> orphanedObjects = cache.GetItemsInContainer(ItemCacheContainer.Objects);

                // We check both successful and failed results.
                foreach (ItemCacheContainer resultsContainer in new ItemCacheContainer[] { ItemCacheContainer.Results, ItemCacheContainer.FailedResults })
                {
                    HashSet<string> parseErrors = new HashSet<string>();

                    // Misfiled results (i.e. failures in Results container or
                    // non-failures in FailedResults container).
                    HashSet<string> misfiledResults = new HashSet<string>();

                    // Results that are missing one or more ouput objects.
                    HashSet<string> resultsMissingOutputs = new HashSet<string>();

                    HashSet<string> missingOutputHashes = new HashSet<string>();
                    HashSet<string> missingOutputPaths = new HashSet<string>();
                    int timeouts = 0;
                    int failures = 0;
                    int missing = 0;

                    HashSet<string> results = cache.GetItemsInContainer(resultsContainer);
                    foreach (string result in results)
                    {
                        ResultSummaryRecord record = FetchRecord(cache, resultsContainer, result);
                        if (record == null)
                        {
                            Console.WriteLine("Parse error in {0}.", result);
                            parseErrors.Add(result);
                        }
                        else
                        {
                            if (record.IsFailure)
                            {
                                if (resultsContainer == ItemCacheContainer.Results)
                                {
                                    // We shouldn't have any failures in Results!
                                    misfiledResults.Add(result);
                                }

                                if (record.IsVerificationTimeout)
                                {
                                    ////Console.WriteLine("Timeout in {0}.", result);
                                    timeouts++;
                                }
                                else
                                {
                                    ////Console.WriteLine("Failure in {0}.", result);
                                    failures++;
                                }
                            }
                            else if (resultsContainer == ItemCacheContainer.FailedResults)
                            {
                                // We should only have failures in FailedResults!
                                misfiledResults.Add(result);
                            }

                            // Verify each output is in the cache.
                            bool hasMissingOuputs = false;
                            foreach (BuildObjectValuePointer output in record.Outputs)
                            {
                                if (objects.Contains(output.ObjectHash))
                                {
                                    // Output present in object cache.
                                    // Remove it from orphaned objects list.
                                    orphanedObjects.Remove(output.ObjectHash);
                                }
                                else if (sources.Contains(output.ObjectHash))
                                {
                                    // Output present in sources cache.
                                    Console.WriteLine("Has 'source' file listed as an output: {0}!", result);
                                }
                                else
                                {
                                    // Output missing from both object and sources caches.
                                    hasMissingOuputs = true;
                                    missingOutputHashes.Add(output.ObjectHash);
                                    missingOutputPaths.Add(output.RelativePath);
                                    missing++;
                                    Console.WriteLine("Missing Output Listed in {0}, Object {1} ({2}).", result, output.ObjectHash, output.RelativePath);
                                }
                            }

                            if (hasMissingOuputs)
                            {
                                resultsMissingOutputs.Add(result);
                            }
                        }
                    }

                    Console.WriteLine();
                    Console.WriteLine("Checked {0} results in {1} cache {2} container:", results.Count, cache.Name, resultsContainer.ToString());
                    Console.WriteLine("Corrupted (parsing errors or otherwise unreadable): {0}", parseErrors.Count);
                    Console.WriteLine("Filed in wrong container: {0}", misfiledResults.Count);
                    Console.WriteLine("Timeouts: {0}, Other failures: {1}, Total failures: {2}", timeouts, failures, timeouts + failures);
                    Console.WriteLine("Missing at least one output object: {0}", resultsMissingOutputs.Count);
                    Console.WriteLine("Total missing output objects: {0}, Unique contents: {1}, Unique paths: {2}", missing, missingOutputHashes.Count, missingOutputPaths.Count);
                    Console.WriteLine();

                    if (cleanup)
                    {
                        if (misfiledResults.Count != 0)
                        {
                            Console.Write("Deleting misfiled results...");
                            foreach (string misfiledResult in misfiledResults)
                            {
                                cache.DeleteItem(resultsContainer, misfiledResult);
                            }

                            Console.WriteLine("Done.");
                        }

                        if (resultsMissingOutputs.Count != 0)
                        {
                            Console.Write("Deleting results with missing outputs...");
                            foreach (string resultMissingOutputs in resultsMissingOutputs)
                            {
                                cache.DeleteItem(resultsContainer, resultMissingOutputs);
                            }

                            Console.WriteLine("Done.");
                        }

                        Console.WriteLine();
                    }
                }

                // REVIEW: in at least one instance, we cache an intermediate
                // object that isn't referenced by a result.  That instance is
                // DafnyIncludes.ExpandDafny(), which is called from
                // DafnyCompileOneVerb.  This is to allow cloud execution of the
                // process invoke part of the verb's execution (with the dafny
                // expansion happening in the verb's getWorker() method).  Since
                // ExpandDafny() is a work-around for a Dafny issue, it's not
                // clear whether we should further accommodate this in the build
                // system (i.e. by making ExpandDafny its own verb) or not.
                // At any rate, having orphaned objects is not necessarily bad.
                Console.WriteLine("Orphaned objects not listed in any result: {0}", orphanedObjects.Count);

                if (cleanup)
                {
                    Console.WriteLine();

                    if (orphanedObjects.Count != 0)
                    {
                        Console.Write("Deleting orphaned objects...");
                        foreach (string orphanedObject in orphanedObjects)
                        {
                            cache.DeleteItem(ItemCacheContainer.Objects, orphanedObject);
                        }

                        Console.WriteLine("Done.");
                    }
                }
            }
        }