Perf: Don't call "GetReferencedAssemblies" when loading extensions

GetReferencedAssemblies forces all assemblies to be loaded, which has an impact
on startup time. Since we know the name of the assemblies we need to load for
extensions/modules, do a assembly name check instead.

Also refactor code paths to always use the IBuildManager abstraction.

--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-07-02 23:37:33 -07:00
parent 6ff8f611db
commit 6c2ee38bd3
10 changed files with 84 additions and 51 deletions

View File

@@ -1,4 +1,5 @@
using System.CodeDom.Compiler;
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -11,6 +12,12 @@ namespace Orchard.Environment.Extensions.Compilers {
/// Note: Currently not used...
/// </summary>
public class CSharpExtensionDirectoryCompiler {
private readonly IBuildManager _buildManager;
public CSharpExtensionDirectoryCompiler(IBuildManager buildManager) {
_buildManager = buildManager;
}
public CompilerResults CompileProject(string location) {
var codeProvider = CodeDomProvider.CreateProvider("cs");
@@ -23,10 +30,11 @@ namespace Orchard.Environment.Extensions.Compilers {
}
private IEnumerable<string> GetAssemblyReferenceNames() {
return Enumerable.Distinct<string>(BuildManager.GetReferencedAssemblies()
.OfType<Assembly>()
.Select(x => x.Location)
.Where(x => !string.IsNullOrEmpty(x)));
return _buildManager
.GetReferencedAssemblies()
.Select(x => x.Location)
.Where(x => !string.IsNullOrEmpty(x))
.Distinct(StringComparer.OrdinalIgnoreCase);
}
private IEnumerable<string> GetSourceFileNames(string path) {

View File

@@ -96,7 +96,7 @@ namespace Orchard.Environment.Extensions {
foreach (var probe in extensionProbes) {
Logger.Debug(" Loader: {0}", probe.Loader.Name);
Logger.Debug(" VirtualPath: {0}", probe.VirtualPath);
Logger.Debug(" DateTimeUtc: {0}", probe.LastModificationTimeUtc);
Logger.Debug(" DateTimeUtc: {0}", probe.LastWriteTimeUtc);
}
}
@@ -162,7 +162,7 @@ namespace Orchard.Environment.Extensions {
.Where(probe => probe != null))
.GroupBy(e => e.Descriptor.Name)
.ToDictionary(g => g.Key, g => g.AsEnumerable()
.OrderByDescending(probe => probe.LastModificationTimeUtc)
.OrderByDescending(probe => probe.LastWriteTimeUtc)
.ThenBy(probe => probe.Loader.Order), StringComparer.OrdinalIgnoreCase);
var deletedDependencies = previousDependencies
@@ -222,57 +222,50 @@ namespace Orchard.Environment.Extensions {
string referenceName,
IList<DependencyReferenceDescriptor> activatedReferences) {
// Assemblies loaded by the BuildManager are ignored, since
// we don't want to update them and they are automatically
// referenced by the build manager
if (_buildManager.GetReferencedAssemblies().Any(a => StringComparer.OrdinalIgnoreCase.Equals(a.GetName().Name, referenceName)))
return;
// Binary references
var references = context.ReferencesByName.ContainsKey(referenceName) ?
context.ReferencesByName[referenceName] :
Enumerable.Empty<ExtensionReferenceProbeEntry>();
// Binary references
var bestBinaryReference = references
.Where(entry => !string.IsNullOrEmpty(entry.VirtualPath))
.Select(entry => new { Entry = entry, LastWriteTimeUtc = _virtualPathProvider.GetFileLastWriteTimeUtc(entry.VirtualPath) })
.OrderBy(e => e.LastWriteTimeUtc)
.ThenBy(e => e.Entry.Name).FirstOrDefault();
.ThenBy(e => e.Name).FirstOrDefault();
var bestProbe = context.ProcessedExtensions.ContainsKey(referenceName) ?
var bestExtensionReference = context.ProcessedExtensions.ContainsKey(referenceName) ?
context.ProcessedExtensions[referenceName] :
null;
// Pick the best one of module vs binary
if (bestProbe != null && bestBinaryReference != null) {
if (bestProbe.LastModificationTimeUtc >= bestBinaryReference.LastWriteTimeUtc) {
if (bestExtensionReference != null && bestBinaryReference != null) {
if (bestExtensionReference.LastWriteTimeUtc >= bestBinaryReference.LastWriteTimeUtc) {
bestBinaryReference = null;
}
else {
bestProbe = null;
bestExtensionReference = null;
}
}
// Activate the binary ref
if (bestBinaryReference != null) {
if (!context.ProcessedReferences.Contains(bestBinaryReference.Entry.Name)) {
context.ProcessedReferences.Add(bestBinaryReference.Entry.Name);
bestBinaryReference.Entry.Loader.ReferenceActivated(context, bestBinaryReference.Entry);
if (!context.ProcessedReferences.Contains(bestBinaryReference.Name)) {
context.ProcessedReferences.Add(bestBinaryReference.Name);
bestBinaryReference.Loader.ReferenceActivated(context, bestBinaryReference);
}
activatedReferences.Add(new DependencyReferenceDescriptor {
LoaderName = bestBinaryReference.Entry.Loader.Name,
Name = bestBinaryReference.Entry.Name,
VirtualPath = bestBinaryReference.Entry.VirtualPath
LoaderName = bestBinaryReference.Loader.Name,
Name = bestBinaryReference.Name,
VirtualPath = bestBinaryReference.VirtualPath
});
return;
}
// Activated the module ref
if (bestProbe != null) {
if (bestExtensionReference != null) {
activatedReferences.Add(new DependencyReferenceDescriptor {
LoaderName = bestProbe.Loader.Name,
LoaderName = bestExtensionReference.Loader.Name,
Name = referenceName,
VirtualPath = bestProbe.VirtualPath
VirtualPath = bestExtensionReference.VirtualPath
});
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Linq;
using System.Reflection;
using Orchard.Environment.Extensions.Models;
@@ -23,7 +23,7 @@ namespace Orchard.Environment.Extensions.Loaders {
return new ExtensionProbeEntry {
Descriptor = descriptor,
Loader = this,
LastModificationTimeUtc = DateTime.MinValue,
LastWriteTimeUtc = DateTime.MinValue,
VirtualPath = "~/Areas/" + descriptor.Name,
};
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Linq;
using System.Reflection;
using Orchard.Environment.Extensions.Models;
@@ -25,7 +25,7 @@ namespace Orchard.Environment.Extensions.Loaders {
if (descriptor.Location == "~/Core") {
return new ExtensionProbeEntry {
Descriptor = descriptor,
LastModificationTimeUtc = DateTime.MinValue,
LastWriteTimeUtc = DateTime.MinValue,
Loader = this,
VirtualPath = "~/Core/" + descriptor.Name
};

View File

@@ -107,7 +107,7 @@ namespace Orchard.Environment.Extensions.Loaders {
return new ExtensionProbeEntry {
Descriptor = descriptor,
LastModificationTimeUtc = _virtualPathProvider.GetFileLastWriteTimeUtc(projectPath),
LastWriteTimeUtc = _virtualPathProvider.GetFileLastWriteTimeUtc(projectPath),
Loader = this,
VirtualPath = projectPath
};

View File

@@ -10,7 +10,7 @@ namespace Orchard.Environment.Extensions.Loaders {
public ExtensionDescriptor Descriptor { get; set; }
public IExtensionLoader Loader { get; set; }
public string VirtualPath { get; set; }
public DateTime LastModificationTimeUtc { get; set; }
public DateTime LastWriteTimeUtc { get; set; }
}
public class ExtensionReferenceProbeEntry {
@@ -18,6 +18,7 @@ namespace Orchard.Environment.Extensions.Loaders {
public IExtensionLoader Loader { get; set; }
public string Name { get; set; }
public string VirtualPath { get; set; }
public DateTime LastWriteTimeUtc { get; set; }
}
public interface IExtensionLoader {

View File

@@ -138,7 +138,8 @@ namespace Orchard.Environment.Extensions.Loaders {
Descriptor = descriptor,
Loader = this,
Name = Path.GetFileNameWithoutExtension(path),
VirtualPath = path
VirtualPath = path,
LastWriteTimeUtc = _virtualPathProvider.GetFileLastWriteTimeUtc(path)
} );
}
@@ -160,7 +161,7 @@ namespace Orchard.Environment.Extensions.Loaders {
return new ExtensionProbeEntry {
Descriptor = descriptor,
LastModificationTimeUtc = File.GetLastWriteTimeUtc(_virtualPathProvider.MapPath(assemblyPath)),
LastWriteTimeUtc = _virtualPathProvider.GetFileLastWriteTimeUtc(assemblyPath),
Loader = this,
VirtualPath = assemblyPath
};

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using Orchard.Environment.Extensions.Models;
using Orchard.FileSystems.Dependencies;
@@ -86,7 +86,7 @@ namespace Orchard.Environment.Extensions.Loaders {
return new ExtensionProbeEntry {
Descriptor = descriptor,
LastModificationTimeUtc = _assemblyProbingFolder.GetAssemblyDateTimeUtc(descriptor.Name),
LastWriteTimeUtc = _assemblyProbingFolder.GetAssemblyDateTimeUtc(descriptor.Name),
Loader = this,
VirtualPath = desc.VirtualPath
};

View File

@@ -1,4 +1,5 @@
using System.IO;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web.Compilation;
@@ -14,11 +15,13 @@ namespace Orchard.Environment.Extensions.Loaders {
/// </summary>
public class ReferencedExtensionLoader : ExtensionLoaderBase {
private readonly IVirtualPathProvider _virtualPathProvider;
private readonly IBuildManager _buildManager;
public ReferencedExtensionLoader(IDependenciesFolder dependenciesFolder, IVirtualPathProvider virtualPathProvider)
public ReferencedExtensionLoader(IDependenciesFolder dependenciesFolder, IVirtualPathProvider virtualPathProvider, IBuildManager buildManager)
: base(dependenciesFolder) {
_virtualPathProvider = virtualPathProvider;
_buildManager = buildManager;
Logger = NullLogger.Instance;
}
@@ -49,16 +52,13 @@ namespace Orchard.Environment.Extensions.Loaders {
if (HostingEnvironment.IsHosted == false)
return null;
var assembly = BuildManager.GetReferencedAssemblies()
.OfType<Assembly>()
.FirstOrDefault(x => x.GetName().Name == descriptor.Name);
var assembly = _buildManager.GetReferencedAssembly(descriptor.Name);
if (assembly == null)
return null;
return new ExtensionProbeEntry {
Descriptor = descriptor,
LastModificationTimeUtc = File.GetLastWriteTimeUtc(assembly.Location),
LastWriteTimeUtc = File.GetLastWriteTimeUtc(assembly.Location),
Loader = this,
VirtualPath = _virtualPathProvider.Combine("~/bin", descriptor.Name + ".dll")
};
@@ -68,10 +68,7 @@ namespace Orchard.Environment.Extensions.Loaders {
if (HostingEnvironment.IsHosted == false)
return null;
var assembly = BuildManager.GetReferencedAssemblies()
.OfType<Assembly>()
.FirstOrDefault(x => x.GetName().Name == descriptor.Name);
var assembly = _buildManager.GetReferencedAssembly(descriptor.Name);
if (assembly == null)
return null;

View File

@@ -1,21 +1,54 @@
using System.Linq;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using System.Web.Compilation;
using Orchard.FileSystems.VirtualPath;
namespace Orchard.Environment {
public interface IBuildManager : IDependency {
IEnumerable<Assembly> GetReferencedAssemblies();
Assembly GetReferencedAssembly(string name);
Assembly GetCompiledAssembly(string virtualPath);
}
public class DefaultBuildManager : IBuildManager {
private readonly IVirtualPathProvider _virtualPathProvider;
public DefaultBuildManager(IVirtualPathProvider virtualPathProvider) {
_virtualPathProvider = virtualPathProvider;
}
public IEnumerable<Assembly> GetReferencedAssemblies() {
return BuildManager.GetReferencedAssemblies().OfType<Assembly>();
}
public Assembly GetReferencedAssembly(string name) {
var assemblyPath = _virtualPathProvider.Combine("~/bin", name + ".dll");
if (!_virtualPathProvider.FileExists(assemblyPath))
return null;
return Assembly.Load(name);
}
public Assembly GetCompiledAssembly(string virtualPath) {
return BuildManager.GetCompiledAssembly(virtualPath);
}
}
public static class BuildManagerExtensions {
public static IEnumerable<string> GetReferencedAssemblyNames(this IBuildManager buildManager) {
return buildManager
.GetReferencedAssemblies()
.Select(a => ExtractAssemblyName(a.FullName));
}
public static string ExtractAssemblyName(string fullName) {
int index = fullName.IndexOf(',');
if (index < 0)
return fullName;
return fullName.Substring(0, index);
}
}
}