private void CollectInputReferences(AssetDependencies dependencyRoot, AssetId assetId, HashSet <AssetId> visited, bool recursive, ContentLinkType linkTypes, ref int count) { if (visited != null) { if (visited.Contains(assetId)) { return; } visited.Add(assetId); } count++; AssetDependencies dependencies; Dependencies.TryGetValue(assetId, out dependencies); if (dependencies != null) { foreach (var pair in dependencies.LinksIn) { if ((linkTypes & pair.Type) != 0) { dependencyRoot.AddLinkIn(pair); if (visited != null && recursive) { CollectInputReferences(dependencyRoot, pair.Item.Id, visited, true, linkTypes, ref count); } } } } }
private void UpdateAssetDependencies(AssetDependencies dependencies) { lock (ThisLock) { // Remove previous missing dependencies RemoveMissingDependencies(dependencies); // Remove [In] dependencies from previous children foreach (var referenceAsset in dependencies.LinksOut) { var childDependencyItem = TrackAsset(referenceAsset.Item); childDependencyItem?.RemoveLinkIn(dependencies.Item); } // Recalculate [Out] dependencies CollectDynamicOutReferences(dependencies, FindAssetFromDependencyOrSession, false, true); // Add [In] dependencies to new children foreach (var assetLink in dependencies.LinksOut) { var childDependencyItem = TrackAsset(assetLink.Item); childDependencyItem?.AddLinkIn(dependencies.Item, assetLink.Type); } // Update missing dependencies UpdateMissingDependencies(dependencies); } }
public AssetDependencies(AssetDependencies set) { if (set == null) { throw new ArgumentNullException("set"); } item = set.Item; // Copy Output refs foreach (var child in set.LinksOut) { AddLinkOut(child); } // Copy Input refs foreach (var child in set.LinksIn) { AddLinkIn(child); } // Copy missing refs foreach (var child in set.BrokenLinksOut) { AddBrokenLinkOut(child.Element, child.Type); } }
public IEnumerable <IContentLink> GetDependencies(AssetItem item) { dependencies = new AssetDependencies(item); Visit(item.Asset); return(dependencies.BrokenLinksOut); }
private void RemoveMissingDependencies(AssetDependencies dependencies) { if (AssetsWithMissingReferences.ContainsKey(dependencies.Item.Id)) { AssetsWithMissingReferences.Remove(dependencies.Item.Id); foreach (var assetLink in dependencies.BrokenLinksOut) { var list = MissingReferencesToParent[assetLink.Element.Id]; list.Remove(dependencies); if (list.Count == 0) { MissingReferencesToParent.Remove(assetLink.Element.Id); } } } }
private void UpdateMissingDependencies(AssetDependencies dependencies) { HashSet <AssetDependencies> parentDependencyItems; // If the asset has any missing dependencies, update the fast lookup tables if (dependencies.HasMissingDependencies) { AssetsWithMissingReferences[dependencies.Item.Id] = dependencies; foreach (var assetLink in dependencies.BrokenLinksOut) { if (!MissingReferencesToParent.TryGetValue(assetLink.Element.Id, out parentDependencyItems)) { parentDependencyItems = new HashSet <AssetDependencies>(); MissingReferencesToParent.Add(assetLink.Element.Id, parentDependencyItems); } parentDependencyItems.Add(dependencies); } } var item = dependencies.Item; // If the new asset was a missing reference, remove all missing references for this asset if (MissingReferencesToParent.TryGetValue(item.Id, out parentDependencyItems)) { MissingReferencesToParent.Remove(item.Id); foreach (var parentDependencies in parentDependencyItems) { // Remove missing dependency from parent var oldBrokenLink = parentDependencies.RemoveBrokenLinkOut(item.Id); // Update [Out] dependency to parent parentDependencies.AddLinkOut(item, oldBrokenLink.Type); // Update [In] dependency to current dependencies.AddLinkIn(parentDependencies.Item, oldBrokenLink.Type); // Remove global cache for assets with missing references if (!parentDependencies.HasMissingDependencies) { AssetsWithMissingReferences.Remove(parentDependencies.Item.Id); } } } }
/// <summary> /// This method is called when an asset needs to be tracked /// </summary> /// <returns>AssetDependencies.</returns> private AssetDependencies TrackAsset(AssetId assetId) { lock (ThisLock) { AssetDependencies dependencies; if (Dependencies.TryGetValue(assetId, out dependencies)) { return(dependencies); } // TODO provide an optimized version of TrackAsset method // taking directly a well known asset (loaded from a Package...etc.) // to avoid session.FindAsset var assetItem = session.FindAsset(assetId); if (assetItem == null) { return(null); } // Clone the asset before using it in this instance to make sure that // we have some kind of immutable state // TODO: This is not handling shadow registry // No need to clone assets from readonly package var assetItemCloned = assetItem.Package.IsSystem ? assetItem : new AssetItem(assetItem.Location, AssetCloner.Clone(assetItem.Asset), assetItem.Package) { SourceFolder = assetItem.SourceFolder, AlternativePath = assetItem.AlternativePath, }; dependencies = new AssetDependencies(assetItemCloned); // Adds to global list Dependencies.Add(assetId, dependencies); // Update dependencies UpdateAssetDependencies(dependencies); CheckAllDependencies(); return(dependencies); } }
private void CollectOutputReferences(AssetDependencies dependencyRoot, AssetId assetId, HashSet <AssetId> visited, bool recursive, ContentLinkType linkTypes, ref int count) { if (visited != null) { if (visited.Contains(assetId)) { return; } visited.Add(assetId); } count++; var dependencies = CalculateDependencies(assetId); if (dependencies == null) { return; } // Add missing references foreach (var missingRef in dependencies.BrokenLinksOut) { dependencyRoot.AddBrokenLinkOut(missingRef); } // Add output references foreach (var child in dependencies.LinksOut) { if ((linkTypes & child.Type) != 0) { dependencyRoot.AddLinkOut(child); if (visited != null && recursive) { CollectOutputReferences(dependencyRoot, child.Item.Id, visited, true, linkTypes, ref count); } } } }
/// <inheritdoc /> public AssetDependencies ComputeDependencies(AssetId assetId, AssetDependencySearchOptions dependenciesOptions = AssetDependencySearchOptions.All, ContentLinkType linkTypes = ContentLinkType.Reference, HashSet <AssetId> visited = null) { bool recursive = (dependenciesOptions & AssetDependencySearchOptions.Recursive) != 0; if (visited == null && recursive) { visited = new HashSet <AssetId>(); } //var clock = Stopwatch.StartNew(); lock (Initialize()) { AssetDependencies dependencies; if (!Dependencies.TryGetValue(assetId, out dependencies)) { return(null); } dependencies = new AssetDependencies(dependencies.Item); int inCount = 0, outCount = 0; if ((dependenciesOptions & AssetDependencySearchOptions.In) != 0) { CollectInputReferences(dependencies, assetId, visited, recursive, linkTypes, ref inCount); } if ((dependenciesOptions & AssetDependencySearchOptions.Out) != 0) { visited?.Clear(); CollectOutputReferences(dependencies, assetId, visited, recursive, linkTypes, ref outCount); } //Console.WriteLine("Time to compute dependencies: {0}ms in: {1} out:{2}", clock.ElapsedMilliseconds, inCount, outCount); return(dependencies); } }
/// <summary> /// Collects all references of an asset dynamically. /// </summary> /// <param name="result">The result.</param> /// <param name="assetResolver">The asset resolver.</param> /// <param name="isRecursive">if set to <c>true</c> collects references recursively.</param> /// <param name="keepParents">Indicate if the parent of the provided <paramref name="result"/> should be kept or not</param> /// <exception cref="System.ArgumentNullException"> /// result /// or /// assetResolver /// </exception> private static void CollectDynamicOutReferences(AssetDependencies result, Func <AssetId, AssetItem> assetResolver, bool isRecursive, bool keepParents) { if (result == null) { throw new ArgumentNullException(nameof(result)); } if (assetResolver == null) { throw new ArgumentNullException(nameof(assetResolver)); } var addedReferences = new HashSet <AssetId>(); var itemsToAnalyze = new Queue <AssetItem>(); var referenceCollector = new DependenciesCollector(); // Reset the dependencies/parts. result.Reset(keepParents); var assetItem = result.Item; // marked as processed to not add it again addedReferences.Add(assetItem.Id); itemsToAnalyze.Enqueue(assetItem); while (itemsToAnalyze.Count > 0) { var item = itemsToAnalyze.Dequeue(); foreach (var link in referenceCollector.GetDependencies(item)) { if (addedReferences.Contains(link.Element.Id)) { continue; } // marked as processed to not add it again addedReferences.Add(link.Element.Id); // add the location to the reference location list var nextItem = assetResolver(link.Element.Id); if (nextItem != null) { result.AddLinkOut(nextItem, link.Type); // add current element to analyze list, to analyze dependencies recursively if (isRecursive) { itemsToAnalyze.Enqueue(nextItem); } } else { result.AddBrokenLinkOut(link); } } if (!isRecursive) { break; } } }