mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Improve performance of GetFeaturesThatNeedUpdate
This improves (~25%) the response time of _every_ admin page, as the GetFeaturesThatNeedUpdate method is called once per page to figure out if an admin notification should be displayed about features needed to update. There were 2 issues: 1. Using (and compiling) a regular expression is expensive to match a simple "UpdateFrom[n]" pattern. 2. Reading each row of the data migration table is more expensive than reading everything in one shot (the number of rows is alway going to be small, as there is one row per feature) --HG-- branch : dev
This commit is contained in:
@@ -2,13 +2,11 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Orchard.ContentManagement.MetaData;
|
using Orchard.ContentManagement.MetaData;
|
||||||
using Orchard.Data.Migration.Interpreters;
|
using Orchard.Data.Migration.Interpreters;
|
||||||
using Orchard.Data.Migration.Records;
|
using Orchard.Data.Migration.Records;
|
||||||
using Orchard.Data.Migration.Schema;
|
using Orchard.Data.Migration.Schema;
|
||||||
using Orchard.Environment.Extensions;
|
using Orchard.Environment.Extensions;
|
||||||
using Orchard.Environment.State;
|
|
||||||
using Orchard.Localization;
|
using Orchard.Localization;
|
||||||
using Orchard.Logging;
|
using Orchard.Logging;
|
||||||
|
|
||||||
@@ -41,38 +39,17 @@ namespace Orchard.Data.Migration {
|
|||||||
public ILogger Logger { get; set; }
|
public ILogger Logger { get; set; }
|
||||||
|
|
||||||
public IEnumerable<string> GetFeaturesThatNeedUpdate() {
|
public IEnumerable<string> GetFeaturesThatNeedUpdate() {
|
||||||
|
var currentVersions = _dataMigrationRepository.Table.ToDictionary(r => r.DataMigrationClass);
|
||||||
|
|
||||||
var features = new List<string>();
|
var outOfDateMigrations = _dataMigrations.Where(dataMigration => {
|
||||||
|
DataMigrationRecord record;
|
||||||
|
if (currentVersions.TryGetValue(dataMigration.GetType().FullName, out record))
|
||||||
|
return CreateUpgradeLookupTable(dataMigration).ContainsKey(record.Version);
|
||||||
|
|
||||||
// compare current version and available migration methods for each migration class
|
return (GetCreateMethod(dataMigration) != null);
|
||||||
foreach ( var dataMigration in _dataMigrations ) {
|
});
|
||||||
|
|
||||||
// get current version for this migration
|
|
||||||
var dataMigrationRecord = GetDataMigrationRecord(dataMigration);
|
|
||||||
|
|
||||||
var current = 0;
|
return outOfDateMigrations.Select(m => m.Feature.Descriptor.Id).ToList();
|
||||||
if (dataMigrationRecord != null) {
|
|
||||||
current = dataMigrationRecord.Version;
|
|
||||||
}
|
|
||||||
|
|
||||||
// do we need to call Create() ?
|
|
||||||
if (current == 0) {
|
|
||||||
|
|
||||||
// try to resolve a Create method
|
|
||||||
if ( GetCreateMethod(dataMigration) != null ) {
|
|
||||||
features.Add(dataMigration.Feature.Descriptor.Id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var lookupTable = CreateUpgradeLookupTable(dataMigration);
|
|
||||||
|
|
||||||
if(lookupTable.ContainsKey(current)) {
|
|
||||||
features.Add(dataMigration.Feature.Descriptor.Id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return features;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(IEnumerable<string> features) {
|
public void Update(IEnumerable<string> features) {
|
||||||
@@ -206,20 +183,26 @@ namespace Orchard.Data.Migration {
|
|||||||
/// Create a list of all available Update methods from a data migration class, indexed by the version number
|
/// Create a list of all available Update methods from a data migration class, indexed by the version number
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static Dictionary<int, MethodInfo> CreateUpgradeLookupTable(IDataMigration dataMigration) {
|
private static Dictionary<int, MethodInfo> CreateUpgradeLookupTable(IDataMigration dataMigration) {
|
||||||
var updateMethodNameRegex = new Regex(@"^UpdateFrom(?<version>\d+)$", RegexOptions.Compiled);
|
return dataMigration
|
||||||
|
.GetType()
|
||||||
|
.GetMethods(BindingFlags.Public | BindingFlags.Instance)
|
||||||
|
.Select(mi => GetUpdateMethod(mi))
|
||||||
|
.Where(tuple => tuple != null)
|
||||||
|
.ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2);
|
||||||
|
}
|
||||||
|
|
||||||
// update methods might also be called after Create()
|
private static Tuple<int, MethodInfo> GetUpdateMethod(MethodInfo mi) {
|
||||||
var lookupTable = new Dictionary<int, MethodInfo>();
|
const string updatefromPrefix = "UpdateFrom";
|
||||||
|
|
||||||
// construct a lookup table with all managed initial versions
|
if (mi.Name.StartsWith(updatefromPrefix)) {
|
||||||
foreach ( var methodInfo in dataMigration.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance) ) {
|
var version = mi.Name.Substring(updatefromPrefix.Length);
|
||||||
var match = updateMethodNameRegex.Match(methodInfo.Name);
|
int versionValue;
|
||||||
if ( match.Success ) {
|
if (int.TryParse(version, out versionValue)) {
|
||||||
lookupTable.Add(int.Parse(match.Groups["version"].Value), methodInfo);
|
return new Tuple<int, MethodInfo>(versionValue, mi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lookupTable;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
Reference in New Issue
Block a user