| File: MetadataCache.cs | Web Access |
| Project: src\sdk\src\RazorSdk\Tool\Microsoft.NET.Sdk.Razor.Tool.csproj (rzc) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #nullable disable using System.Diagnostics; using System.Reflection.PortableExecutable; using Microsoft.CodeAnalysis; namespace Microsoft.NET.Sdk.Razor.Tool { internal class MetadataCache { // Store 1000 entries -- arbitrary number private const int CacheSize = 1000; private readonly ConcurrentLruCache<string, MetadataCacheEntry> _metadataCache = new(CacheSize, StringComparer.OrdinalIgnoreCase); // For testing purposes only. internal ConcurrentLruCache<string, MetadataCacheEntry> Cache => _metadataCache; internal Metadata GetMetadata(string fullPath) { var timestamp = GetFileTimeStamp(fullPath); // Check if we have an entry in the dictionary. if (_metadataCache.TryGetValue(fullPath, out var entry)) { if (timestamp.HasValue && timestamp.Value == entry.Timestamp) { // The file has not changed since we cached it. Return the cached entry. return entry.Metadata; } else { // The file has changed recently. Remove the cache entry. _metadataCache.Remove(fullPath); } } Metadata metadata; using (var fileStream = File.OpenRead(fullPath)) { metadata = AssemblyMetadata.CreateFromStream(fileStream, PEStreamOptions.PrefetchMetadata); } _metadataCache.GetOrAdd(fullPath, new MetadataCacheEntry(timestamp.Value, metadata)); return metadata; } private static DateTime? GetFileTimeStamp(string fullPath) { try { Debug.Assert(Path.IsPathRooted(fullPath)); return File.GetLastWriteTimeUtc(fullPath); } catch (Exception e) { // 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 and log. ServerLogger.LogException(e, $"Error getting timestamp of file {fullPath}."); return null; } } internal struct MetadataCacheEntry { public MetadataCacheEntry(DateTime timestamp, Metadata metadata) { Debug.Assert(timestamp.Kind == DateTimeKind.Utc); Timestamp = timestamp; Metadata = metadata; } public DateTime Timestamp { get; } public Metadata Metadata { get; } } } }