|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// THE ASSEMBLY BUILT FROM THIS SOURCE FILE HAS BEEN DEPRECATED FOR YEARS. IT IS BUILT ONLY TO PROVIDE
// BACKWARD COMPATIBILITY FOR API USERS WHO HAVE NOT YET MOVED TO UPDATED APIS. PLEASE DO NOT SEND PULL
// REQUESTS THAT CHANGE THIS FILE WITHOUT FIRST CHECKING WITH THE MAINTAINERS THAT THE FIX IS REQUIRED.
using System;
using System.Collections;
using System.Collections.Generic;
namespace Microsoft.Build.BuildEngine
{
/// <summary>
/// Internal enum for distinguishing between cache content types
/// </summary>
internal enum CacheContentType
{
// Cached build results for targets - only accessible internally from the engine
BuildResults = 0,
// Items cached from tasks
Items = 1,
// Properties cached from tasks
Properties = 2,
LastContentTypeIndex = 2
}
/// <summary>
/// This class is responsible for maintaining the set of object
/// cached during a build session. This class is not thread safe and
/// is intended to be used from the Engine thread.
/// </summary>
internal class CacheManager
{
#region Constructors
internal CacheManager(string defaultVersion)
{
cacheContents = new Hashtable[(int)CacheContentType.LastContentTypeIndex + 1];
for (int i = 0; i < (int)CacheContentType.LastContentTypeIndex + 1; i++)
{
cacheContents[i] = new Hashtable(StringComparer.OrdinalIgnoreCase);
}
this.defaultToolsVersion = defaultVersion;
}
#endregion
#region Properties
#endregion
#region Methods
private CacheScope GetCacheScopeIfExists(string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType)
{
CacheScope cacheScope = null;
// Default the version to the default engine version
if (scopeToolsVersion == null)
{
scopeToolsVersion = defaultToolsVersion;
}
// Retrieve list of scopes by this name
if (cacheContents[(int)cacheContentType].ContainsKey(scopeName))
{
List<CacheScope> scopesByName = (List<CacheScope>)cacheContents[(int)cacheContentType][scopeName];
// If the list exists search for matching scope properties otherwise create the list
if (scopesByName != null)
{
lock (cacheManagerLock)
{
for (int i = 0; i < scopesByName.Count; i++)
{
if (scopesByName[i].ScopeProperties.IsEquivalent(scopeProperties) && (String.Equals(scopeToolsVersion, scopesByName[i].ScopeToolsVersion, StringComparison.OrdinalIgnoreCase)))
{
cacheScope = scopesByName[i];
break;
}
}
}
}
}
return cacheScope;
}
/// <summary>
/// This method return a cache scope with particular name and properties. If the cache
/// scope doesn't exist it will be created. This method is thread safe.
/// </summary>
internal CacheScope GetCacheScope(string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType)
{
// If the version is not specified default to the engine version
if (scopeToolsVersion == null)
{
scopeToolsVersion = defaultToolsVersion;
}
// Retrieve the cache scope if it exists
CacheScope cacheScope = GetCacheScopeIfExists(scopeName, scopeProperties, scopeToolsVersion, cacheContentType);
// If the scope doesn't exist create it
if (cacheScope == null)
{
lock (cacheManagerLock)
{
cacheScope = GetCacheScopeIfExists(scopeName, scopeProperties, scopeToolsVersion, cacheContentType);
if (cacheScope == null)
{
// If the list of scopes doesn't exist create it
if (!cacheContents[(int)cacheContentType].ContainsKey(scopeName))
{
cacheContents[(int)cacheContentType].Add(scopeName, new List<CacheScope>());
}
// Create the scope and add it to the list
List<CacheScope> scopesByName = (List<CacheScope>)cacheContents[(int)cacheContentType][scopeName];
cacheScope = new CacheScope(scopeName, scopeProperties, scopeToolsVersion);
scopesByName.Add(cacheScope);
}
}
}
return cacheScope;
}
/// <summary>
/// Sets multiple cache entries for the given scope
/// </summary>
/// <param name="entries"></param>
/// <param name="scopeName"></param>
/// <param name="scopeProperties"></param>
internal void SetCacheEntries(CacheEntry[] entries, string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType)
{
// If the list exists search for matching scope properties otherwise create the list
CacheScope cacheScope = GetCacheScope(scopeName, scopeProperties, scopeToolsVersion, cacheContentType);
// Add the entry to the right scope
cacheScope.AddCacheEntries(entries);
}
/// <summary>
/// Gets multiple cache entries from the given scope.
/// </summary>
/// <param name="names"></param>
/// <param name="scopeName"></param>
/// <param name="scopeProperties"></param>
/// <returns></returns>
internal CacheEntry[] GetCacheEntries(string[] names, string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType)
{
CacheScope cacheScope = GetCacheScopeIfExists(scopeName, scopeProperties, scopeToolsVersion, cacheContentType);
if (cacheScope != null)
{
return cacheScope.GetCacheEntries(names);
}
return new CacheEntry[names.Length];
}
/// <summary>
/// This method get a result from the cache if every target is cached.
/// If any of the target are not present in the cache null is returned. This method is not thread safe.
/// </summary>
internal BuildResult GetCachedBuildResult(BuildRequest buildRequest, out ArrayList actuallyBuiltTargets)
{
actuallyBuiltTargets = null;
if (!buildRequest.UseResultsCache)
{
return null;
}
// Retrieve list of scopes by this name
string projectName = buildRequest.ProjectToBuild == null ?
buildRequest.ProjectFileName : buildRequest.ProjectToBuild.FullFileName;
// If the list exists search for matching scope properties otherwise create the list
CacheScope cacheScope = GetCacheScopeIfExists(projectName, buildRequest.GlobalProperties, buildRequest.ToolsetVersion, CacheContentType.BuildResults);
// If there is no cache entry for this project return null
if (cacheScope == null)
{
return null;
}
return cacheScope.GetCachedBuildResult(buildRequest, out actuallyBuiltTargets);
}
/// <summary>
/// Clear a particular scope
/// </summary>
/// <param name="projectName"></param>
/// <param name="buildPropertyGroup"></param>
/// <param name="toolsVersion"></param>
internal void ClearCacheScope(string projectName, BuildPropertyGroup buildPropertyGroup, string toolsVersion, CacheContentType cacheContentType)
{
// Retrieve list of scopes by this name
if (cacheContents[(int)cacheContentType].ContainsKey(projectName))
{
List<CacheScope> scopesByName = (List<CacheScope>)cacheContents[(int)cacheContentType][projectName];
// If the list exists search for matching scope properties otherwise create the list
if (scopesByName != null)
{
// If the version is not specified default to the engine version
if (toolsVersion == null)
{
toolsVersion = defaultToolsVersion;
}
lock (cacheManagerLock)
{
for (int i = 0; i < scopesByName.Count; i++)
{
if (scopesByName[i].ScopeProperties.IsEquivalent(buildPropertyGroup) && (String.Equals(toolsVersion, scopesByName[i].ScopeToolsVersion, StringComparison.OrdinalIgnoreCase)))
{
scopesByName.RemoveAt(i);
break;
}
}
}
}
}
}
/// <summary>
/// Clears the whole contents of the cache.
/// </summary>
internal void ClearCache()
{
// Abandon the old cache contents
for (int i = 0; i < (int)CacheContentType.LastContentTypeIndex + 1; i++)
{
cacheContents[i] = new Hashtable(StringComparer.OrdinalIgnoreCase);
}
}
#endregion
#region Data
// Array of cache contents per namespace
private Hashtable[] cacheContents;
// Lock object for the cache manager
private object cacheManagerLock = new object();
// The default toolset version
private string defaultToolsVersion;
#endregion
}
}
|