private Task <CompatibilityProfileCacheEntry> GetUnionProfile(DirectoryInfo profileDir) { IEnumerable <string> profilePaths = profileDir.EnumerateFiles("*.json") .Where(file => file.Name.IndexOf("union", StringComparison.OrdinalIgnoreCase) < 0) // Filter out union files .Select(file => file.FullName); IEnumerable <CompatibilityProfileCacheEntry> profiles = GetProfilesFromPaths(profilePaths).Result; string unionId = GetUnionIdFromProfiles(profiles); string unionPath = Path.Combine(profileDir.FullName, unionId + ".json"); return(_profileCache.GetOrAdd(unionPath, new Lazy <Task <CompatibilityProfileCacheEntry> >(() => Task.Run(() => { try { // We read the ID first to avoid needing to rehydrate MBs of unneeded JSON if (JsonProfileSerializer.ReadIdFromProfileFile(unionPath) == unionId) { CompatibilityProfileDataMut loadedUnionProfile = _jsonSerializer.DeserializeFromFile(unionPath); // This is unlikely, but the ID has limited entropy if (UnionMatchesProfiles(loadedUnionProfile, profiles)) { return new CompatibilityProfileCacheEntry( loadedUnionProfile, new CompatibilityProfileData(loadedUnionProfile)); } } // We found the union file, but it didn't match for some reason File.Delete(unionPath); } catch (Exception) { // Do nothing, we will now generate the profile } // Loading the union file failed, so we are forced to generate it CompatibilityProfileDataMut generatedUnionProfile = ProfileCombination.UnionMany(unionId, profiles.Select(p => p.MutableProfileData)); // Write the union to the filesystem for faster startup later Task.Run(() => { _jsonSerializer.SerializeToFile(generatedUnionProfile, unionPath); }); return new CompatibilityProfileCacheEntry( generatedUnionProfile, new CompatibilityProfileData(generatedUnionProfile)); }))).Value); }
/// <summary> /// Create a new compatibility profile loader with an empty cache. /// </summary> public CompatibilityProfileLoader() { _jsonSerializer = JsonProfileSerializer.Create(); // Cache keys are filenames, which must be case-insensitive in Windows and macOS #if CORECLR if (System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { _profileCache = new ConcurrentDictionary <string, Lazy <Task <CompatibilityProfileCacheEntry> > >(); } else { _profileCache = new ConcurrentDictionary <string, Lazy <Task <CompatibilityProfileCacheEntry> > >(StringComparer.OrdinalIgnoreCase); } #else _profileCache = new ConcurrentDictionary <string, Lazy <Task <CompatibilityProfileCacheEntry> > >(StringComparer.OrdinalIgnoreCase); #endif }