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.");
}
}
}
}