/// <summary> /// Returns true if the given cache entry contains equivalent contents /// </summary> /// <param name="other"></param> /// <returns></returns> internal override bool IsEquivalent(CacheEntry other) { if ((other == null) || (other.GetType() != this.GetType())) { return false; } BuildItemCacheEntry otherEntry = (BuildItemCacheEntry)other; if (this.Name != otherEntry.Name) { return false; } if ((this.BuildItems == null && otherEntry.BuildItems != null) || (this.BuildItems != null && otherEntry.BuildItems == null)) { return false; } if ((this.BuildItems == null) && (otherEntry.BuildItems == null)) { return true; } if (this.BuildItems.Length != otherEntry.BuildItems.Length) { return false; } for (int i = 0; i < this.BuildItems.Length; i++) { if ((this.BuildItems[i] == null && otherEntry.BuildItems[i] != null) || (this.BuildItems[i] != null && otherEntry.BuildItems[i] == null)) { return false; } if ((this.BuildItems[i].FinalItemSpecEscaped != otherEntry.BuildItems[i].FinalItemSpecEscaped) || (this.BuildItems[i].GetCustomMetadataCount() != otherEntry.BuildItems[i].GetCustomMetadataCount())) { return false; } ArrayList otherEntryMetadataNames = new ArrayList(otherEntry.BuildItems[i].GetAllCustomMetadataNames()); foreach (string metadataName in this.BuildItems[i].GetAllCustomMetadataNames()) { if ((!otherEntryMetadataNames.Contains(metadataName)) || (this.BuildItems[i].GetEvaluatedMetadataEscaped(metadataName) != otherEntry.BuildItems[i].GetEvaluatedMetadataEscaped(metadataName))) { return false; } } } return true; }
/// <summary> /// Called on the main node only. /// </summary> public Exception PostCacheEntriesToHost(int nodeId, CacheEntry[] entries, string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType) { try { parentEngine.CacheManager.SetCacheEntries(entries, scopeName, scopeProperties, scopeToolsVersion, cacheContentType); } catch (InvalidOperationException e) { return e; } return null; }
/// <summary> /// Returns true if the given cache entry contains equivalent contents /// </summary> /// <param name="other"></param> /// <returns></returns> internal override bool IsEquivalent(CacheEntry other) { if ((other == null) || (other.GetType() != this.GetType())) { return false; } if (!base.IsEquivalent(other)) { return false; } return (this.BuildResult == ((BuildResultCacheEntry)other).BuildResult); }
/// <summary> /// Returns true if the given cache entry contains equivalent contents /// </summary> /// <param name="other"></param> /// <returns></returns> internal override bool IsEquivalent(CacheEntry other) { if ((other == null) || (other.GetType() != this.GetType())) { return false; } PropertyCacheEntry otherEntry = (PropertyCacheEntry)other; if (this.Name != otherEntry.Name) { return false; } return (this.Value == otherEntry.Value); }
internal static void WriteToStream(CacheEntry entry, BinaryWriter writer) { Type entryType = entry.GetType(); if (typeof(BuildItemCacheEntry) == entryType) { writer.Write((byte)CacheEntryTypes.BuildItem); entry.WriteToStream(writer); } else if (typeof(BuildResultCacheEntry) == entryType) { writer.Write((byte)CacheEntryTypes.BuildResult); entry.WriteToStream(writer); } else if (typeof(PropertyCacheEntry) == entryType) { writer.Write((byte)CacheEntryTypes.Property); entry.WriteToStream(writer); } }
/// <summary> /// Called either on the main or child node. This is the routing method for setting cache entries. /// </summary> public void SetCacheEntries ( int handleId, CacheEntry[] entries, string cacheScope, string cacheKey, string cacheVersion, CacheContentType cacheContentType, bool localNodeOnly ) { TaskExecutionContext executionContext = GetTaskContextFromHandleId(handleId); BuildPropertyGroup scopeProperties; if (cacheKey == null) { Project parentProject = executionContext.ParentProject; scopeProperties = parentProject.GlobalProperties; } else { // Property values are compared using case sensitive comparisons because the case of property values do have meaning. // In this case we are using properties in a manner where we do not want case sensitive comparisons. // There is not enough benefit for this one special case to add case insensitive // comparisons to build properties. We instead uppercase all of the keys for both get and set CachedEntries. scopeProperties = new BuildPropertyGroup(); scopeProperties.SetProperty("CacheKey", cacheKey.ToUpper(CultureInfo.InvariantCulture)); } if (cacheScope == null) { cacheScope = executionContext.ParentProject.FullFileName; } if (cacheVersion == null) { cacheVersion = executionContext.ParentProject.ToolsVersion; } parentEngine.CacheManager.SetCacheEntries(entries, cacheScope, scopeProperties, cacheVersion, cacheContentType); // Also send these to the parent if we're allowed to if (parentEngine.Router.ChildMode && !localNodeOnly) { Exception exception = parentEngine.Router.ParentNode.PostCacheEntriesToHost(entries, cacheScope, scopeProperties, cacheVersion, cacheContentType); // If we had problems on the parent node, rethrow the exception here if (exception != null) { throw exception; } } }
internal override void CreateFromStream(BinaryReader reader) { base.CreateFromStream(reader); requestingCallNumber = reader.ReadInt32(); if (reader.ReadByte() == 0) { replyData = null; } else { if (reader.ReadByte() == 0) { int numberOfEntries = reader.ReadInt32(); CacheEntry[] cacheArray = new CacheEntry[numberOfEntries]; for (int i = 0; i < numberOfEntries; i++) { if (reader.ReadByte() == 0) { cacheArray[i] = null; } else { cacheArray[i] = CacheEntryCustomSerializer.CreateFromStream(reader); } } replyData = cacheArray; } else { replyData = formatter.Deserialize(reader.BaseStream); } } }
internal LocalCallDescriptorForPostingCacheEntriesToHost(CacheEntry[] entries, string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType) : base(LocalCallType.PostCacheEntriesToHost) { this.entries = entries; this.scopeName = scopeName; this.scopeProperties = scopeProperties; this.scopeToolsVersion = scopeToolsVersion; this.cacheContentType = cacheContentType; this.exception = null; }
/// <summary> /// Returns true if the given cache entry contains equivalent contents /// </summary> /// <param name="other"></param> /// <returns></returns> internal abstract bool IsEquivalent(CacheEntry other);
/// <summary> /// This method adds multiple entries to the cache in a thread-safe way. /// </summary> /// <param name="cacheEntries"></param> internal void AddCacheEntries(CacheEntry[] cacheEntries) { cacheScopeReaderWriterLock.AcquireWriterLock(Timeout.Infinite); try { for (int i = 0; i < cacheEntries.Length; i++) { if (cacheEntries[i] != null) { AddCacheEntryInternal(cacheEntries[i]); } } } finally { cacheScopeReaderWriterLock.ReleaseWriterLock(); } }
private void VerifyGetCacheEntries(CacheEntry[] entries) { Assert.IsTrue(entries[0] is BuildItemCacheEntry); Assert.IsTrue(string.Compare(entries[0].Name, "Badger" , StringComparison.OrdinalIgnoreCase) == 0); BuildItem[] buildItemArray = ((BuildItemCacheEntry)entries[0]).BuildItems; Assert.IsTrue(buildItemArray.Length == 2); Assert.IsTrue(string.Compare(buildItemArray[0].Include, "TestInclude1", StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(string.Compare(buildItemArray[1].Include, "TestInclude2", StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(string.Compare(buildItemArray[1].Name, "BuildItem2", StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(entries[1] is BuildResultCacheEntry); Assert.IsTrue(string.Compare(entries[1].Name, "Koi", StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(((BuildResultCacheEntry)entries[1]).BuildResult); buildItemArray = ((BuildResultCacheEntry)entries[1]).BuildItems; Assert.IsTrue(buildItemArray.Length == 2); Assert.IsTrue(string.Compare(buildItemArray[0].Include, "TestInclude1", StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(string.Compare(buildItemArray[1].Include, "TestInclude2", StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(string.Compare(buildItemArray[1].Name, "BuildItem2", StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(entries[2] is PropertyCacheEntry); Assert.IsTrue(string.Compare(((PropertyCacheEntry)entries[2]).Name, "Seagull", StringComparison.OrdinalIgnoreCase) == 0); Assert.IsTrue(string.Compare(((PropertyCacheEntry)entries[2]).Value, "bread", StringComparison.OrdinalIgnoreCase) == 0); }
/// <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> /// Send the cache entries to the parent engine /// </summary> /// <param name="nodeId"></param> /// <param name="entries"></param> /// <param name="scopeName"></param> /// <param name="scopeProperties"></param> public Exception PostCacheEntriesToHost(int nodeId, CacheEntry[] entries, string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType) { LocalCallDescriptorForPostingCacheEntriesToHost callDescriptor = new LocalCallDescriptorForPostingCacheEntriesToHost(entries, scopeName, scopeProperties, scopeToolsVersion, cacheContentType); return (Exception)GetReplyForCallDescriptor(callDescriptor); }
/// <summary> /// This method adds an entry to the cache in a thread-safe way /// </summary> internal void AddCacheEntry(CacheEntry cacheEntry) { cacheScopeReaderWriterLock.AcquireWriterLock(Timeout.Infinite); try { if (cacheEntry != null) { AddCacheEntryInternal(cacheEntry); } } finally { cacheScopeReaderWriterLock.ReleaseWriterLock(); } }
/// <summary> /// This method returns the requested set of cache entries. This method is thread safe /// </summary> /// <param name="names"></param> /// <returns></returns> internal CacheEntry[] GetCacheEntries(string[] names) { CacheEntry[] results = new CacheEntry[names.Length]; // This is read only, but since we're processing multiple entries we want to present a consistent // view of the cache... we don't want a write between our reads cacheScopeReaderWriterLock.AcquireReaderLock(Timeout.Infinite); try { for (int i = 0; i < names.Length; i++) { results[i] = GetCacheEntry(names[i]); } } finally { cacheScopeReaderWriterLock.ReleaseReaderLock(); } return results; }
/// <summary> /// This method adds an entry to the cache, without taking a lock /// </summary> private void AddCacheEntryInternal(CacheEntry cacheEntry) { if (!cacheContents.ContainsKey(cacheEntry.Name)) { cacheContents.Add(cacheEntry.Name, cacheEntry); } else { CacheEntry existingCacheEntry = (CacheEntry)cacheContents[cacheEntry.Name]; // Make sure the cache values, if overwritten, stay the same. We do not currently support // changing the cached value to something else. This allows us to not have a notification // mechanism for changed values and if a node has a cached entry it can assume it's up to date. // This can change in the future if we discover a compelling scenario for changing cache values. if (!cacheEntry.IsEquivalent(existingCacheEntry)) { ErrorUtilities.VerifyThrowInvalidOperation(false, "CannotModifyCacheEntryValues"); } } }
/// <summary> /// Posts the given set of cache entries to the parent engine. /// </summary> /// <param name="entries"></param> /// <param name="scopeName"></param> /// <param name="scopeProperties"></param> internal Exception PostCacheEntriesToHost(CacheEntry[] entries, string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType) { try { return parentCallback.PostCacheEntriesToHost(this.nodeId /* ignored */, entries, scopeName, scopeProperties, scopeToolsVersion, cacheContentType); } catch (Exception e) { ReportUnhandledError(e); return null; } }
private static CacheEntry[] CreateCacheEntries() { CacheEntry[] entries = new CacheEntry[3]; BuildItem buildItem1 = new BuildItem("BuildItem1", "Item1"); BuildItem buildItem2 = new BuildItem("BuildItem2", "Item2"); buildItem1.Include = "TestInclude1"; buildItem2.Include = "TestInclude2"; BuildItem[] buildItems = new BuildItem[2]; buildItems[0] = buildItem1; buildItems[1] = buildItem2; entries[0] = new BuildItemCacheEntry("Badger", buildItems); entries[1] = new BuildResultCacheEntry("Koi", buildItems, true); entries[2] = new PropertyCacheEntry("Seagull", "bread"); return entries; }