private async Task <bool> ValidateContentDirectoryAsync(Context context) { _tracer.Always(context, "Validating local CAS content directory"); int contentDirectoryMismatchCount = 0; var fileSystemContentDirectory = _enumerateBlobPathsFromDisk() .Select(blobPath => FileSystemContentStoreInternal.TryGetHashFromPath(blobPath.FullPath, out var hash) ? (ContentHash?)hash : null) .Where(hash => hash != null) .GroupBy(hash => hash !.Value) .ToDictionary(replicaGroup => replicaGroup.Key, replicaGroup => replicaGroup.Count()); foreach (var x in fileSystemContentDirectory.Keys) { var fileSystemHash = x; int fileSystemHashReplicaCount = fileSystemContentDirectory[fileSystemHash]; await _contentDirectory.UpdateAsync(fileSystemHash, false, _clock, fileInfo => { if (fileInfo == null) { contentDirectoryMismatchCount++; _tracer.Always(context, $"Cache content directory for hash {fileSystemHash.ToShortString()} from disk does not exist."); } else if (fileInfo.ReplicaCount != fileSystemHashReplicaCount) { contentDirectoryMismatchCount++; _tracer.Always( context, $"Directory for hash {fileSystemHash.ToShortString()} describes {fileInfo.ReplicaCount} replicas, but {fileSystemHashReplicaCount} replicas exist on disk."); } return(null); }); } foreach (var x in (await _contentDirectory.EnumerateContentHashesAsync()) .Where(hash => !fileSystemContentDirectory.ContainsKey(hash))) { var missingHash = x; contentDirectoryMismatchCount++; await _contentDirectory.UpdateAsync(missingHash, false, _clock, fileInfo => { if (fileInfo != null) { _tracer.Always( context, $"Directory for hash {missingHash.ToShortString()} describes {fileInfo.ReplicaCount} replicas, but no replicas exist on disk."); } return(null); }); } _tracer.Always( context, $"{contentDirectoryMismatchCount} mismatches between cache content directory and content files on disk."); return(contentDirectoryMismatchCount == 0); }