private void AddItemsToCache(ImmutableHashSet <string> globsToIgnore, OrderedItemDataCollection items) { if (_cache == null) { _cache = new Dictionary <ISet <string>, OrderedItemDataCollection>(); } _cache[globsToIgnore] = items; }
public bool TryGetFromCache(ISet <string> globsToIgnore, out OrderedItemDataCollection items) { if (_cache != null) { return(_cache.TryGetValue(globsToIgnore, out items)); } items = null; return(false); }
private static OrderedItemDataCollection.Builder ComputeItems(LazyItemList lazyItemList, ImmutableHashSet <string> globsToIgnore) { // Stack of operations up to the first one that's cached (exclusive) Stack <LazyItemList> itemListStack = new Stack <LazyItemList>(); OrderedItemDataCollection.Builder items = null; // Keep a separate stack of lists of globs to ignore that only gets modified for Remove operations Stack <ImmutableHashSet <string> > globsToIgnoreStack = null; for (var currentList = lazyItemList; currentList != null; currentList = currentList._previous) { var globsToIgnoreFromFutureOperations = globsToIgnoreStack?.Peek() ?? globsToIgnore; OrderedItemDataCollection itemsFromCache; if (currentList._memoizedOperation.TryGetFromCache(globsToIgnoreFromFutureOperations, out itemsFromCache)) { // the base items on top of which to apply the uncached operations are the items of the first operation that is cached items = itemsFromCache.ToBuilder(); break; } // If this is a remove operation, then add any globs that will be removed // to a list of globs to ignore in previous operations if (currentList._memoizedOperation.Operation is RemoveOperation removeOperation) { globsToIgnoreStack ??= new Stack <ImmutableHashSet <string> >(); var globsToIgnoreForPreviousOperations = removeOperation.GetRemovedGlobs(); foreach (var globToRemove in globsToIgnoreFromFutureOperations) { globsToIgnoreForPreviousOperations.Add(globToRemove); } globsToIgnoreStack.Push(globsToIgnoreForPreviousOperations.ToImmutable()); } itemListStack.Push(currentList); } if (items == null) { items = OrderedItemDataCollection.CreateBuilder(); } ImmutableHashSet <string> currentGlobsToIgnore = globsToIgnoreStack == null ? globsToIgnore : globsToIgnoreStack.Peek(); Dictionary <string, UpdateOperation> itemsWithNoWildcards = new Dictionary <string, UpdateOperation>(StringComparer.OrdinalIgnoreCase); bool addedToBatch = false; // Walk back down the stack of item lists applying operations while (itemListStack.Count > 0) { var currentList = itemListStack.Pop(); if (currentList._memoizedOperation.Operation is UpdateOperation op) { bool addToBatch = true; int i; // The TextFragments are things like abc.def or x*y.*z. for (i = 0; i < op.Spec.Fragments.Count; i++) { ItemSpecFragment frag = op.Spec.Fragments[i]; if (MSBuildConstants.CharactersForExpansion.Any(frag.TextFragment.Contains)) { // Fragment contains wild cards, items, or properties. Cannot batch over it using a dictionary. addToBatch = false; break; } string fullPath = FileUtilities.GetFullPath(frag.TextFragment, frag.ProjectDirectory); if (itemsWithNoWildcards.ContainsKey(fullPath)) { // Another update will already happen on this path. Make that happen before evaluating this one. addToBatch = false; break; } else { itemsWithNoWildcards.Add(fullPath, op); } } if (!addToBatch) { // We found a wildcard. Remove any fragments associated with the current operation and process them later. for (int j = 0; j < i; j++) { itemsWithNoWildcards.Remove(currentList._memoizedOperation.Operation.Spec.Fragments[j].TextFragment); } } else { addedToBatch = true; continue; } } if (addedToBatch) { addedToBatch = false; ProcessNonWildCardItemUpdates(itemsWithNoWildcards, items); } // If this is a remove operation, then it could modify the globs to ignore, so pop the potentially // modified entry off the stack of globs to ignore if (currentList._memoizedOperation.Operation is RemoveOperation) { globsToIgnoreStack.Pop(); currentGlobsToIgnore = globsToIgnoreStack.Count == 0 ? globsToIgnore : globsToIgnoreStack.Peek(); } currentList._memoizedOperation.Apply(items, currentGlobsToIgnore); } // We finished looping through the operations. Now process the final batch if necessary. ProcessNonWildCardItemUpdates(itemsWithNoWildcards, items); return(items); }