提交 ddd11e47 编写于 作者: H heejaechang

added cache option and made caches to listen to them.

now cache size can be changed and dynamically configured if we want. (changeset 1308740)
上级 71b441c8
......@@ -96,6 +96,14 @@ public bool Remove(T value)
return dictionary.TryRemove(value, out b);
}
/// <summary>
/// Clear the set
/// </summary>
public void Clear()
{
dictionary.Clear();
}
public struct KeyEnumerator
{
private readonly IEnumerator<KeyValuePair<T, byte>> kvpEnumerator;
......
......@@ -502,9 +502,9 @@ private static ValueSource<Compilation> GetCompilation(Project project, Compilat
return new ConstantValueSource<Compilation>(compilation);
}
if (project.Solution.BranchId == workspace.PrimaryBranchId && compilationCache.Primary != null)
if (project.Solution.BranchId == workspace.PrimaryBranchId)
{
return new CachedObjectSource<Compilation>(compilation, compilationCache.Primary);
return new CachedObjectSource<Compilation>(compilation, compilationCache);
}
return new ConstantValueSource<Compilation>(compilation);
......
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.Host
{
internal abstract class AbstractCacheServiceFactory : IWorkspaceServiceFactory
{
private IWorkspaceService cache = null;
protected abstract int InitialMinimumCount { get; }
protected abstract long InitialCacheSize { get; }
protected abstract IWorkspaceService CreateCache(IOptionService service);
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
if (cache == null)
{
var service = workspaceServices.GetService<IOptionService>();
var newCache = CreateCache(service);
Interlocked.CompareExchange(ref cache, newCache, null);
}
return cache;
}
protected void GetInitialCacheValues(IOptionService service, Option<int> minimumCountKey, Option<long> sizeKey, out int minimumCount, out long size)
{
if (service == null)
{
minimumCount = InitialMinimumCount;
size = InitialCacheSize;
}
minimumCount = service.GetOption(minimumCountKey);
size = service.GetOption(sizeKey);
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.Host
{
internal static class CacheOptions
{
public const string FeatureName = "Cache Options";
[ExportOption]
public static readonly Option<long> TextCacheSize = new Option<long>(FeatureName, "Default Text Cache Size", defaultValue: TextCacheServiceFactory.CacheSize);
[ExportOption]
public static readonly Option<int> TextCacheCount = new Option<int>(FeatureName, "Default Minimum Text Count In The Cache", defaultValue: TextCacheServiceFactory.TextCount);
[ExportOption]
public static readonly Option<long> SyntaxTreeCacheSize = new Option<long>(FeatureName, "Default SyntaxTree Cache Size", defaultValue: SyntaxTreeCacheServiceFactory.CacheSize);
[ExportOption]
public static readonly Option<int> SyntaxTreeCacheCount = new Option<int>(FeatureName, "Default Minimum SyntaxTree Count In The Cache", defaultValue: SyntaxTreeCacheServiceFactory.TreeCount);
[ExportOption]
public static readonly Option<long> CompilationCacheSize = new Option<long>(FeatureName, "Default Compilation Cache Size", defaultValue: CompilationCacheServiceFactory.CacheSize);
[ExportOption]
public static readonly Option<int> CompilationCacheCount = new Option<int>(FeatureName, "Default Minimum Compilation Count In The Cache", defaultValue: CompilationCacheServiceFactory.CompilationCount);
}
}
......@@ -2,69 +2,69 @@
using System;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.Host
{
[ExportWorkspaceServiceFactory(typeof(ICompilationCacheService), ServiceLayer.Default)]
internal partial class CompilationCacheServiceFactory : IWorkspaceServiceFactory
internal partial class CompilationCacheServiceFactory : AbstractCacheServiceFactory
{
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
public const long CacheSize = 1000;
public const int CompilationCount = 2;
protected override IWorkspaceService CreateCache(IOptionService service)
{
return new CompilationCacheService();
int count;
long size;
GetInitialCacheValues(service, CacheOptions.CompilationCacheCount, CacheOptions.CompilationCacheSize, out count, out size);
return new CompilationCacheService(service, count, size);
}
private class CompilationCacheService : ICompilationCacheService
protected override long InitialCacheSize
{
public CompilationCacheService()
get
{
// this will basically slowly push up current cache threshold but
// fastly bring it down to the normal threshold.
this.Primary = new CompilationCache();
// this one will push up and down threshold fast but at the end
// will not leave anything in the cache.
this.Secondary = new CompilationCache(
increment: 100,
minimumCompilationsCount: 0,
defaultTotalCostForAllCompilations: 0,
eagarlyEvict: true);
return CacheSize;
}
}
public ICompilationCache Primary { get; private set; }
public ICompilationCache Secondary { get; private set; }
public void Clear()
protected override int InitialMinimumCount
{
get
{
this.Primary.Clear();
this.Secondary.Clear();
return CompilationCount;
}
}
private class CompilationCache : CostBasedCache<Compilation>, ICompilationCache
private class CompilationCacheService : CostBasedCache<Compilation>, ICompilationCacheService
{
// this will make cache size to be half in about 3 seconds with 500ms buffer time.
private const double CoolingRate = 0.00006;
private const int Increment = 1;
private const int MinimumCompilationsCount = 2;
private const long DefaultTotalCostForAllCompilations = 1000;
private const long MaxTotalCostForAllCompilations = 10000;
private const int UpperBoundRatio = 10;
public CompilationCacheService(IOptionService service, int minCount, long minCost)
: base(service, minCount, minCost, minCost * UpperBoundRatio,
CoolingRate, Increment, TimeSpan.FromMilliseconds(500), // Keep all added compilations at least 500ms
ComputeCompilationCost, false, GetUniqueId)
{
}
internal CompilationCache(
int increment = Increment,
int minimumCompilationsCount = MinimumCompilationsCount,
long defaultTotalCostForAllCompilations = DefaultTotalCostForAllCompilations,
bool eagarlyEvict = false)
: base(
minimumCompilationsCount,
defaultTotalCostForAllCompilations,
MaxTotalCostForAllCompilations,
CoolingRate,
Increment,
TimeSpan.FromMilliseconds(500), // Keep all added compilations at least 500ms
ComputeCompilationCost,
eagarlyEvict,
GetUniqueId)
protected override void OnOptionChanged(OptionChangedEventArgs e)
{
if (e.Option == CacheOptions.CompilationCacheCount)
{
this.minCount = (int)e.Value;
}
else if (e.Option == CacheOptions.CompilationCacheSize)
{
var cost = (long)e.Value;
this.minCost = cost;
this.maxCost = cost * UpperBoundRatio;
}
}
private static string GetUniqueId(Compilation compilation)
......@@ -81,5 +81,4 @@ private static long ComputeCompilationCost(Compilation compilation)
}
}
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.CodeAnalysis.Host
{
internal partial class CostBasedCache<T> : IObjectCache<T> where T : class
{
// entry that holds onto various info
// not a struct since it will be stored in concurrent dictionary as a value
// and that would wrap it into a class anyways
private class CacheEntry
{
public readonly long ItemId;
public readonly int CreatedTime;
public readonly IWeakAction<T> EvictAction;
public DateTime LastTimeAccessed;
public int AccessCount;
public long Cost;
public CacheEntry(long itemId, IWeakAction<T> evictor)
{
this.ItemId = itemId;
this.CreatedTime = Environment.TickCount;
this.EvictAction = evictor;
this.LastTimeAccessed = DateTime.UtcNow;
this.AccessCount = 1;
this.Cost = UnitializedCost;
}
}
private struct SnapshotItem
{
public T Item { get; private set; }
public double Rank { get; private set; }
public CacheEntry Entry { get; private set; }
public SnapshotItem(T item, double rank, CacheEntry entry)
: this()
{
this.Item = item;
this.Rank = rank;
this.Entry = entry;
}
}
}
}
\ No newline at end of file
......@@ -6,6 +6,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Internal.Log;
using Microsoft.CodeAnalysis.Options;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Host
......@@ -26,7 +27,7 @@ namespace Microsoft.CodeAnalysis.Host
///
/// the size of the upper bound will be decreased to its normal level once those activities have ceased.
/// </summary>
internal class CostBasedCache<T> : IObjectCache<T> where T : class
internal partial class CostBasedCache<T> : IObjectCache<T> where T : class
{
// constant to indicate that cost is not evaluated yet.
private const long UnitializedCost = -1;
......@@ -37,29 +38,6 @@ internal class CostBasedCache<T> : IObjectCache<T> where T : class
// cache hit threshold where it would slow down cache decay rate
private const float CacheHitThreshold = 0.8F;
// delegate cache to avoid allocations
private readonly Func<long, T, bool, string> logAddOrAccessed;
private readonly Func<long, int, string> logEvictedOrRemoved;
private readonly Func<T, CacheEntry, CacheEntry> updateCacheEntry;
private readonly Func<KeyValuePair<T, CacheEntry>, double> rankGetter;
private readonly Comparison<SnapshotItem> comparer;
// delegate that will return an identity of a cached item regardless of its version
private readonly Func<T, string> uniqueIdGetter;
// current cache id
private readonly int cacheId;
// evict items without waiting for next item access
private readonly bool eagarlyEvict;
// minimum number of entries to keep in the cache
private readonly int minCount;
// lower and upper bound of the cache in terms of cost
private readonly long minCost;
private readonly long maxCost;
// control variable for exponential decaying algorithm that is used to
// determine current cost upper bound
private readonly int fixedIncrementAmount;
......@@ -79,6 +57,9 @@ internal class CostBasedCache<T> : IObjectCache<T> where T : class
// pre-allocated list to be re-used during eviction
private readonly List<SnapshotItem> evictionCandidateList = new List<SnapshotItem>();
// option service
private readonly IOptionService optionService;
// hold onto last time the task ran
private int lastTimeTaskRan;
......@@ -88,45 +69,29 @@ internal class CostBasedCache<T> : IObjectCache<T> where T : class
// thread that is successful at setting the slot gets to fill it with a running task.
private Task taskSlot;
// cache hit rate for diagnostic purpose
private float cacheHitRate;
// entry that holds onto various info
// not a struct since it will be stored in concurrent dictionary as a value
// and that would wrap it into a class anyways
private class CacheEntry
{
public readonly long ItemId;
public readonly int CreatedTime;
public readonly IWeakAction<T> EvictAction;
public DateTime LastTimeAccessed;
public int AccessCount;
public long Cost;
// evict items without waiting for next item access
protected bool eagarlyEvict;
public CacheEntry(long itemId, IWeakAction<T> evictor)
{
this.ItemId = itemId;
this.CreatedTime = Environment.TickCount;
this.EvictAction = evictor;
// minimum number of entries to keep in the cache
protected int minCount;
this.LastTimeAccessed = DateTime.UtcNow;
this.AccessCount = 1;
this.Cost = UnitializedCost;
}
}
// lower and upper bound of the cache in terms of cost
protected long minCost;
protected long maxCost;
protected CostBasedCache(
IOptionService optionService,
int minCount, long minCost, long maxCost,
double coolingRate, int fixedIncAmount, TimeSpan dataCollectionTimeSpan,
Func<T, long> costCalculator,
Func<T, string> uniqueIdGetter)
: this(minCount, minCost, maxCost, coolingRate, fixedIncAmount,
: this(optionService, minCount, minCost, maxCost, coolingRate, fixedIncAmount,
dataCollectionTimeSpan, costCalculator, false, uniqueIdGetter)
{
}
protected CostBasedCache(
IOptionService optionService,
int minCount, long minCost, long maxCost,
double coolingRate, int fixedIncAmount, TimeSpan dataCollectionTimeSpan,
Func<T, long> costCalculator,
......@@ -167,6 +132,10 @@ public CacheEntry(long itemId, IWeakAction<T> evictor)
this.currentCostUpperBound = minCost;
this.rankGetter = RankingAlgorithm;
// respond to option change
this.optionService = optionService;
this.optionService.OptionChanged += OnOptionChanged;
}
private static double RankingAlgorithm(KeyValuePair<T, CacheEntry> item)
......@@ -359,10 +328,10 @@ private void Evict()
ResetEvictionStates();
EagarlyEvict();
EvictEagarly();
}
private void EagarlyEvict()
private void EvictEagarly()
{
if (!this.eagarlyEvict || this.taskSlot != null || items.Count <= minCount)
{
......@@ -389,41 +358,6 @@ private void EagarlyEvict()
}
}
private void UpdateCacheHitRate(List<SnapshotItem> cacheItems)
{
var cacheHit = 0;
for (int i = 0; i < cacheItems.Count; i++)
{
var item = cacheItems[i];
if (item.Entry.CreatedTime < this.lastTimeTaskRan)
{
cacheHit++;
}
}
// item that has survived last eviction vs new item added after the last eviction
this.cacheHitRate = (float)cacheHit / Math.Max(1, cacheItems.Count);
}
private void LogCacheRankInformation(List<SnapshotItem> snapshot)
{
#if false
// log everything inside of the cache for diagnostic purpose
var now = Environment.TickCount;
Func<SnapshotItem, string> logMessage = i =>
{
return string.Join(",", now, this.cacheId, i.Rank, i.Entry.AccessCount, i.Entry.CreatedTime, i.Entry.LastTimeAccessed, i.Entry.ItemId, this.uniqueIdGetter(i.Item));
};
foreach (var item in snapshot)
{
Logger.Log(FeatureId.Cache, FunctionId.Cache_ItemRank, logMessage, item);
}
#endif
}
private int GetIndexAndCostToDelete(double costUpperBound, List<SnapshotItem> snapshot, out long cost)
{
cost = 0L;
......@@ -518,70 +452,14 @@ public void Clear()
}
}
private string LogAddOrAccessed(long itemId, T item, bool cacheHit)
{
return string.Join(",", cacheId, itemId, item.GetType(), this.uniqueIdGetter(item), cacheHit);
}
private string LogEvictedOrRemoved(long itemId, int accessCount)
{
return string.Join(",", cacheId, itemId, accessCount);
}
private struct SnapshotItem
{
public T Item { get; private set; }
public double Rank { get; private set; }
public CacheEntry Entry { get; private set; }
public SnapshotItem(T item, double rank, CacheEntry entry)
: this()
{
this.Item = item;
this.Rank = rank;
this.Entry = entry;
}
}
// internal information to show in diagnostic
internal long CurrentCostUpperBound
{
get
{
return this.currentCostUpperBound;
}
}
internal int CurrentItemCount
private void OnOptionChanged(object sender, OptionChangedEventArgs e)
{
get
{
return this.items.Count;
}
OnOptionChanged(e);
}
internal long MinCost
protected virtual void OnOptionChanged(OptionChangedEventArgs e)
{
get
{
return this.minCost;
}
}
internal long MaxCost
{
get
{
return this.maxCost;
}
}
internal float CacheHitRate
{
get
{
return this.cacheHitRate;
}
// do nothing
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
namespace Microsoft.CodeAnalysis.Host
{
internal partial class CostBasedCache<T> : IObjectCache<T> where T : class
{
// delegate cache to avoid allocations
private readonly Func<long, T, bool, string> logAddOrAccessed;
private readonly Func<long, int, string> logEvictedOrRemoved;
private readonly Func<T, CacheEntry, CacheEntry> updateCacheEntry;
private readonly Func<KeyValuePair<T, CacheEntry>, double> rankGetter;
private readonly Comparison<SnapshotItem> comparer;
// delegate that will return an identity of a cached item regardless of its version
private readonly Func<T, string> uniqueIdGetter;
// current cache id
private readonly int cacheId;
// cache hit rate for diagnostic purpose
private float cacheHitRate;
private void UpdateCacheHitRate(List<SnapshotItem> cacheItems)
{
var cacheHit = 0;
for (int i = 0; i < cacheItems.Count; i++)
{
var item = cacheItems[i];
if (item.Entry.CreatedTime < this.lastTimeTaskRan)
{
cacheHit++;
}
}
// item that has survived last eviction vs new item added after the last eviction
this.cacheHitRate = (float)cacheHit / Math.Max(1, cacheItems.Count);
}
private void LogCacheRankInformation(List<SnapshotItem> snapshot)
{
#if false
// log everything inside of the cache for diagnostic purpose
var now = Environment.TickCount;
Func<SnapshotItem, string> logMessage = i =>
{
return string.Join(",", now, this.cacheId, i.Rank, i.Entry.AccessCount, i.Entry.CreatedTime, i.Entry.LastTimeAccessed, i.Entry.ItemId, this.uniqueIdGetter(i.Item));
};
foreach (var item in snapshot)
{
Logger.Log(FeatureId.Cache, FunctionId.Cache_ItemRank, logMessage, item);
}
#endif
}
private string LogAddOrAccessed(long itemId, T item, bool cacheHit)
{
return string.Join(",", cacheId, itemId, item.GetType(), this.uniqueIdGetter(item), cacheHit);
}
private string LogEvictedOrRemoved(long itemId, int accessCount)
{
return string.Join(",", cacheId, itemId, accessCount);
}
// internal information to show in diagnostic
internal long CurrentCostUpperBound
{
get
{
return this.currentCostUpperBound;
}
}
internal int CurrentItemCount
{
get
{
return this.items.Count;
}
}
internal long MinimumCost
{
get
{
return this.minCost;
}
}
internal long MaximumCost
{
get
{
return this.maxCost;
}
}
internal float CacheHitRate
{
get
{
return this.cacheHitRate;
}
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Host
{
internal interface ICompilationCache : IObjectCache<Compilation>
{
}
}
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Host
{
internal interface ICompilationCacheService : IWorkspaceService
internal interface ICompilationCacheService : IObjectCache<Compilation>, IWorkspaceService
{
/// <summary>
/// compilation cache for main branch
/// </summary>
ICompilationCache Primary { get; }
/// <summary>
/// compilation cache for all other branches which could include in progress main branch compilation
/// </summary>
ICompilationCache Secondary { get; }
/// <summary>
/// clear compilation caches belong to this workspace
/// </summary>
void Clear();
}
}
......@@ -2,19 +2,40 @@
using System;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.Host
{
[ExportWorkspaceServiceFactory(typeof(ISyntaxTreeCacheService), ServiceLayer.Default)]
internal partial class SyntaxTreeCacheServiceFactory : IWorkspaceServiceFactory
internal partial class SyntaxTreeCacheServiceFactory : AbstractCacheServiceFactory
{
// 4M chars * 2bytes/char = 8MB of raw text, with some syntax nodes deduplicated.
private const long DefaultSize = 4 * 1024 * 1024;
private const int DefaultTextCount = 8;
public const long CacheSize = 4 * 1024 * 1024;
public const int TreeCount = 8;
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
protected override IWorkspaceService CreateCache(IOptionService service)
{
return new SyntaxTreeCacheService(DefaultTextCount, DefaultSize, tv => tv.FullSpan.Length);
int count;
long size;
GetInitialCacheValues(service, CacheOptions.SyntaxTreeCacheCount, CacheOptions.SyntaxTreeCacheSize, out count, out size);
return new SyntaxTreeCacheService(service, count, size, tv => tv.FullSpan.Length);
}
protected override long InitialCacheSize
{
get
{
return CacheSize;
}
}
protected override int InitialMinimumCount
{
get
{
return TreeCount;
}
}
private class SyntaxTreeCacheService : CostBasedCache<SyntaxNode>, ISyntaxTreeCacheService
......@@ -34,12 +55,27 @@ private class SyntaxTreeCacheService : CostBasedCache<SyntaxNode>, ISyntaxTreeCa
private static readonly Func<SyntaxNode, string> uniqueIdGetter =
t => t.SyntaxTree == null ? string.Empty : t.SyntaxTree.FilePath;
public SyntaxTreeCacheService(int minCount, long minCost, Func<SyntaxNode, long> itemCost)
: base(minCount, minCost, minCost * UpperBoundRatio,
public SyntaxTreeCacheService(IOptionService service, int minCount, long minCost, Func<SyntaxNode, long> itemCost)
: base(service, minCount, minCost, minCost * UpperBoundRatio,
CoolingRate, Increment, TimeSpan.FromMilliseconds(500),
itemCost, uniqueIdGetter)
{
}
protected override void OnOptionChanged(OptionChangedEventArgs e)
{
if (e.Option == CacheOptions.SyntaxTreeCacheCount)
{
this.minCount = (int)e.Value;
}
else if (e.Option == CacheOptions.SyntaxTreeCacheSize)
{
var cost = (long)e.Value;
this.minCost = cost;
this.maxCost = cost * UpperBoundRatio;
}
}
}
}
}
\ No newline at end of file
......@@ -2,19 +2,40 @@
using System;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
namespace Microsoft.CodeAnalysis.Host
{
[ExportWorkspaceServiceFactory(typeof(ITextCacheService), ServiceLayer.Default)]
internal partial class TextCacheServiceFactory : IWorkspaceServiceFactory
internal partial class TextCacheServiceFactory : AbstractCacheServiceFactory
{
// 4M chars * 2bytes/char = 8 MB
private const long DefaultSize = 1 << 20;
private const int DefaultTextCount = 8;
// 1M chars * 2bytes/char = 2 MB
public const long CacheSize = 1 << 20;
public const int TextCount = 8;
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
protected override IWorkspaceService CreateCache(IOptionService service)
{
return new TextCacheService(DefaultTextCount, DefaultSize, itemCost: tv => tv.Text.Length);
int count;
long size;
GetInitialCacheValues(service, CacheOptions.TextCacheCount, CacheOptions.TextCacheSize, out count, out size);
return new TextCacheService(service, count, size, itemCost: tv => tv.Text.Length);
}
protected override long InitialCacheSize
{
get
{
return CacheSize;
}
}
protected override int InitialMinimumCount
{
get
{
return TextCount;
}
}
private class TextCacheService : CostBasedCache<TextAndVersion>, ITextCacheService
......@@ -33,9 +54,24 @@ private class TextCacheService : CostBasedCache<TextAndVersion>, ITextCacheServi
private static readonly Func<TextAndVersion, string> uniqueIdGetter = tv => tv.FilePath;
public TextCacheService(int minCount, long minCost, Func<TextAndVersion, long> itemCost)
: base(minCount, minCost, minCost * UpperBoundRatio, CoolingRate, Increment, TimeSpan.FromMilliseconds(200), itemCost, uniqueIdGetter)
public TextCacheService(IOptionService service, int minCount, long minCost, Func<TextAndVersion, long> itemCost)
: base(service, minCount, minCost, minCost * UpperBoundRatio, CoolingRate, Increment, TimeSpan.FromMilliseconds(200), itemCost, uniqueIdGetter)
{
}
protected override void OnOptionChanged(OptionChangedEventArgs e)
{
if (e.Option == CacheOptions.TextCacheCount)
{
this.minCount = (int)e.Value;
}
else if (e.Option == CacheOptions.TextCacheSize)
{
var cost = (long)e.Value;
this.minCost = cost;
this.maxCost = cost * UpperBoundRatio;
}
}
}
}
......
......@@ -728,28 +728,9 @@ internal MetadataReference GetPartialMetadataReference(Solution solution, Projec
/// </summary>
private ValueSource<Compilation> Retain(Solution solution, Compilation compilation)
{
var caches = solution.Services.CompilationCacheService;
if (caches != null)
{
// If the solution supports compilation caches, get the appropriate compilation cache.
// This will ensure the primary compilation cache is not polluted by items from a branched solution.
//
// The secondary cache could get an inProgress compilation that belongs to the primary branch, but as
// soon as the background compiler brings those compilations to their final state, it will be moved to the
// primary cache.
//
// Another case is if a compilation is brought to a final state by a branched solution. The final compilation
// could be in a secondary cache.
//
// We can add a bit more information in the compilation tracker and fork compilation tracker a bit more to let
// it know which branch the compilation tracker belongs to.
//
// But all those cases where a compilation goes to the secondary cache should be either temporary or about ones
// the editor currently doesn't use (no opened file from the compilation).
//
// So, until we have evidence to the contrary, let's leave the logic simple.
var cache = (solution.BranchId == solution.Workspace.PrimaryBranchId) ? caches.Primary : caches.Secondary;
var cache = solution.Services.CompilationCacheService;
if (cache != null)
{
return new CachedObjectSource<Compilation>(compilation, cache);
}
else
......
......@@ -350,6 +350,10 @@
<Compile Include="CodeGeneration\SyntaxAnnotationExtensions.cs" />
<Compile Include="CodeGeneration\TypeGenerator.cs" />
<Compile Include="Utilities\WeakEventHandler.cs" />
<Compile Include="Workspace\Host\Caching\AbstractCacheServiceFactory.cs" />
<Compile Include="Workspace\Host\Caching\CacheOptions.cs" />
<Compile Include="Workspace\Host\Caching\CostBasedCache.Nested.cs" />
<Compile Include="Workspace\Host\Caching\CostBasedCache_Logging.cs" />
<Compile Include="Workspace\Host\Mef\DiagnosticProviderMetadata.cs" />
<Compile Include="Diagnostics\ExportDiagnosticAnalyzerAttribute.cs" />
<Compile Include="Differencing\Edit.cs" />
......@@ -801,7 +805,6 @@
<Compile Include="Workspace\Host\Caching\CacheId.cs" />
<Compile Include="Workspace\Host\Caching\CompilationCacheServiceFactory.cs" />
<Compile Include="Workspace\Host\Caching\CostBasedCache.cs" />
<Compile Include="Workspace\Host\Caching\ICompilationCache.cs" />
<Compile Include="Workspace\Host\Caching\ICompilationCacheService.cs" />
<Compile Include="Workspace\Host\Caching\IObjectCache.cs" />
<Compile Include="Workspace\Host\Caching\ISyntaxTreeCacheService.cs" />
......
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.UnitTests
{
......@@ -16,24 +14,6 @@ public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
}
internal class CacheService : ICompilationCacheService
{
private readonly Cache cache = new Cache();
public ICompilationCache Primary
{
get { return this.cache; }
}
public ICompilationCache Secondary
{
get { return this.cache; }
}
public void Clear()
{
}
private class Cache : ICompilationCache
{
public void AddOrAccess(Compilation instance, IWeakAction<Compilation> evictor)
{
......@@ -45,5 +25,4 @@ public void Clear()
}
}
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册