/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/Server/VBCSCompiler/MetadataCache.cs
139 строк
5 KB
Jared Parsons
Fix the project layout (#61547)
09 июн 2022, 20:42
Не верифицирован
09 июн 2022, 20:42
b6d630f
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Reflection.PortableExecutable; using Microsoft.CodeAnalysis.InternalUtilities; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CompilerServer { internal class MetadataAndSymbolCache { // Store 500 entries -- Out of ~8.7M projects, only about 4,000 had more than 500 references private const int CacheSize = 500; private readonly ConcurrentLruCache<FileKey, Metadata> _metadataCache = new ConcurrentLruCache<FileKey, Metadata>(CacheSize); private ModuleMetadata CreateModuleMetadata(string path, bool prefetchEntireImage) { // TODO: exception handling? var fileStream = FileUtilities.OpenRead(path); var options = PEStreamOptions.PrefetchMetadata; if (prefetchEntireImage) { options |= PEStreamOptions.PrefetchEntireImage; } return ModuleMetadata.CreateFromStream(fileStream, options); } private ImmutableArray<ModuleMetadata> GetAllModules(ModuleMetadata manifestModule, string assemblyDir) { ArrayBuilder<ModuleMetadata>? moduleBuilder = null; foreach (string moduleName in manifestModule.GetModuleNames()) { if (moduleBuilder == null) { moduleBuilder = ArrayBuilder<ModuleMetadata>.GetInstance(); moduleBuilder.Add(manifestModule); } var module = CreateModuleMetadata(PathUtilities.CombineAbsoluteAndRelativePaths(assemblyDir, moduleName)!, prefetchEntireImage: false); moduleBuilder.Add(module); } return (moduleBuilder != null) ? moduleBuilder.ToImmutableAndFree() : ImmutableArray.Create(manifestModule); } internal Metadata GetMetadata(string fullPath, MetadataReferenceProperties properties) { // Check if we have an entry in the dictionary. FileKey? fileKey = GetUniqueFileKey(fullPath); Metadata? metadata; if (fileKey.HasValue && _metadataCache.TryGetValue(fileKey.Value, out metadata) && metadata != null) { return metadata; } if (properties.Kind == MetadataImageKind.Module) { var result = CreateModuleMetadata(fullPath, prefetchEntireImage: true); //?? never add modules to cache? return result; } else { Debug.Assert(fileKey.HasValue); var primaryModule = CreateModuleMetadata(fullPath, prefetchEntireImage: false); // Get all the modules, and load them. Create an assembly metadata. var allModules = GetAllModules(primaryModule, Path.GetDirectoryName(fullPath)!); Metadata result = AssemblyMetadata.Create(allModules); result = _metadataCache.GetOrAdd(fileKey.Value, result); return result; } } /// <summary> /// A unique file key encapsulates a file path, and change date /// that can be used as the key to a dictionary. /// If a file hasn't changed name or timestamp, we assume /// it is unchanged. /// /// Returns null if the file doesn't exist or otherwise can't be accessed. /// </summary> private FileKey? GetUniqueFileKey(string filePath) { try { return FileKey.Create(filePath); } catch (Exception) { // There are several exceptions that can occur here: NotSupportedException or PathTooLongException // for a bad path, UnauthorizedAccessException for access denied, etc. Rather than listing them all, // just catch all exceptions. return null; } } } internal sealed class CachingMetadataReference : PortableExecutableReference { private static readonly MetadataAndSymbolCache s_mdCache = new MetadataAndSymbolCache(); public new string FilePath { get; } public CachingMetadataReference(string fullPath, MetadataReferenceProperties properties) : base(properties, fullPath) { FilePath = fullPath; } protected override DocumentationProvider CreateDocumentationProvider() { return DocumentationProvider.Default; } protected override Metadata GetMetadataImpl() { return s_mdCache.GetMetadata(FilePath, Properties); } protected override PortableExecutableReference WithPropertiesImpl(MetadataReferenceProperties properties) { return new CachingMetadataReference(this.FilePath, properties); } } }