Perf: content manager improvements

Adding adding content manager session to hold items which have been loaded during a request
Altering the routine that determines which version of an item is needed to favor the inmemory collection over direct query where possible

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-05-16 17:02:55 -07:00
parent 04a53cb2d1
commit 8024deca78
5 changed files with 80 additions and 36 deletions

View File

@@ -13,3 +13,4 @@ glob:src/Orchard.Web/Media/*
glob:desktop.ini glob:desktop.ini
glob:src/Orchard.Azure.suo glob:src/Orchard.Azure.suo
glob:log.xml glob:log.xml
glob:profiling

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Autofac; using Autofac;
using Orchard.ContentManagement.Handlers; using Orchard.ContentManagement.Handlers;
@@ -12,16 +13,19 @@ namespace Orchard.ContentManagement {
private readonly IRepository<ContentTypeRecord> _contentTypeRepository; private readonly IRepository<ContentTypeRecord> _contentTypeRepository;
private readonly IRepository<ContentItemRecord> _contentItemRepository; private readonly IRepository<ContentItemRecord> _contentItemRepository;
private readonly IRepository<ContentItemVersionRecord> _contentItemVersionRepository; private readonly IRepository<ContentItemVersionRecord> _contentItemVersionRepository;
private readonly Func<IContentManagerSession> _contentManagerSession;
public DefaultContentManager( public DefaultContentManager(
IComponentContext context, IComponentContext context,
IRepository<ContentTypeRecord> contentTypeRepository, IRepository<ContentTypeRecord> contentTypeRepository,
IRepository<ContentItemRecord> contentItemRepository, IRepository<ContentItemRecord> contentItemRepository,
IRepository<ContentItemVersionRecord> contentItemVersionRepository) { IRepository<ContentItemVersionRecord> contentItemVersionRepository,
Func<IContentManagerSession> contentManagerSession) {
_context = context; _context = context;
_contentTypeRepository = contentTypeRepository; _contentTypeRepository = contentTypeRepository;
_contentItemRepository = contentItemRepository; _contentItemRepository = contentItemRepository;
_contentItemVersionRepository = contentItemVersionRepository; _contentItemVersionRepository = contentItemVersionRepository;
_contentManagerSession = contentManagerSession;
} }
private IEnumerable<IContentHandler> _handlers; private IEnumerable<IContentHandler> _handlers;
@@ -72,45 +76,24 @@ namespace Orchard.ContentManagement {
} }
public virtual ContentItem Get(int id, VersionOptions options) { public virtual ContentItem Get(int id, VersionOptions options) {
var session = _contentManagerSession();
ContentItem contentItem;
ContentItemVersionRecord versionRecord = null; ContentItemVersionRecord versionRecord = null;
var appendLatestVersion = false;
// obtain the root records based on version options // obtain the root records based on version options
if (options.VersionRecordId != 0) { if (options.VersionRecordId != 0) {
// explicit version record known // short-circuit if item held in session
if (session.RecallVersionRecordId(options.VersionRecordId, out contentItem))
return contentItem;
// locate explicit version record
versionRecord = _contentItemVersionRepository.Get(options.VersionRecordId); versionRecord = _contentItemVersionRepository.Get(options.VersionRecordId);
} }
else { else {
// FIX: rework this so it falls back to an in-memory scan when the results don't fit the criteria
var record = _contentItemRepository.Get(id); var record = _contentItemRepository.Get(id);
if (options.IsPublished) { if (record != null)
versionRecord = _contentItemVersionRepository.Get(x => x.ContentItemRecord == record && x.Published); versionRecord = GetVersionRecord(options, record);
}
else if (options.IsLatest) {
versionRecord = _contentItemVersionRepository.Get(x => x.ContentItemRecord == record && x.Latest);
}
else if (options.IsDraft || options.IsDraftRequired) {
versionRecord = _contentItemVersionRepository.Get(x => x.ContentItemRecord == record && x.Latest && !x.Published);
if (versionRecord == null && options.IsDraftRequired) {
versionRecord = _contentItemVersionRepository.Get(x => x.ContentItemRecord == record && x.Latest);
appendLatestVersion = true;
}
}
else if (options.VersionNumber != 0) {
versionRecord = _contentItemVersionRepository.Get(x => x.ContentItemRecord == record && x.Number == options.VersionNumber);
}
//TEMP: this is to transition people with old databases
if (versionRecord == null && record != null && !record.Versions.Any() && options.IsPublished) {
versionRecord = new ContentItemVersionRecord {
ContentItemRecord = record,
Latest = true,
Published = true,
Number = 1
};
record.Versions.Add(versionRecord);
_contentItemVersionRepository.Create(versionRecord);
}
} }
// no record means content item doesn't exist // no record means content item doesn't exist
@@ -118,10 +101,19 @@ namespace Orchard.ContentManagement {
return null; return null;
} }
// return item if obtained earlier in session
if (session.RecallVersionRecordId(versionRecord.Id, out contentItem)) {
return contentItem;
}
// allocate instance and set record property // allocate instance and set record property
var contentItem = New(versionRecord.ContentItemRecord.ContentType.Name); contentItem = New(versionRecord.ContentItemRecord.ContentType.Name);
contentItem.VersionRecord = versionRecord; contentItem.VersionRecord = versionRecord;
// store in session prior to loading to avoid some problems with simple circular dependencies
session.Store(contentItem);
// create a context with a new instance to load // create a context with a new instance to load
var context = new LoadContentContext(contentItem); var context = new LoadContentContext(contentItem);
@@ -133,14 +125,42 @@ namespace Orchard.ContentManagement {
handler.Loaded(context); handler.Loaded(context);
} }
// when draft is required and not currently available a new version is appended // when draft is required and latest is published a new version is appended
if (appendLatestVersion) { if (options.IsDraftRequired && versionRecord.Published) {
return BuildNewVersion(context.ContentItem); return BuildNewVersion(context.ContentItem);
} }
return context.ContentItem; return context.ContentItem;
} }
private ContentItemVersionRecord GetVersionRecord(VersionOptions options, ContentItemRecord itemRecord) {
if (options.IsPublished) {
return itemRecord.Versions.FirstOrDefault(
x => x.Published) ??
_contentItemVersionRepository.Get(
x => x.ContentItemRecord == itemRecord && x.Published);
}
if (options.IsLatest || options.IsDraftRequired) {
return itemRecord.Versions.FirstOrDefault(
x => x.Latest) ??
_contentItemVersionRepository.Get(
x => x.ContentItemRecord == itemRecord && x.Latest);
}
if (options.IsDraft) {
return itemRecord.Versions.FirstOrDefault(
x => x.Latest && !x.Published) ??
_contentItemVersionRepository.Get(
x => x.ContentItemRecord == itemRecord && x.Latest && !x.Published);
}
if (options.VersionNumber != 0) {
return itemRecord.Versions.FirstOrDefault(
x => x.Number == options.VersionNumber) ??
_contentItemVersionRepository.Get(
x => x.ContentItemRecord == itemRecord && x.Number == options.VersionNumber);
}
return null;
}
public virtual IEnumerable<ContentItem> GetAllVersions(int id) { public virtual IEnumerable<ContentItem> GetAllVersions(int id) {
return _contentItemVersionRepository return _contentItemVersionRepository
.Fetch(x => x.ContentItemRecord.Id == id) .Fetch(x => x.ContentItemRecord.Id == id)

View File

@@ -0,0 +1,15 @@
using System.Collections.Generic;
namespace Orchard.ContentManagement {
public class DefaultContentManagerSession : IContentManagerSession {
private readonly IDictionary<int, ContentItem> _itemByVersionRecordId = new Dictionary<int, ContentItem>();
public void Store(ContentItem item) {
_itemByVersionRecordId.Add(item.VersionRecord.Id, item);
}
public bool RecallVersionRecordId(int id, out ContentItem item) {
return _itemByVersionRecordId.TryGetValue(id, out item);
}
}
}

View File

@@ -0,0 +1,6 @@
namespace Orchard.ContentManagement {
public interface IContentManagerSession : IDependency {
void Store(ContentItem item);
bool RecallVersionRecordId(int id, out ContentItem item);
}
}

View File

@@ -150,6 +150,8 @@
<Compile Include="Caching\DefaultCacheManager.cs" /> <Compile Include="Caching\DefaultCacheManager.cs" />
<Compile Include="Caching\ICacheHolder.cs" /> <Compile Include="Caching\ICacheHolder.cs" />
<Compile Include="Caching\Weak.cs" /> <Compile Include="Caching\Weak.cs" />
<Compile Include="ContentManagement\DefaultContentManagerSession.cs" />
<Compile Include="ContentManagement\IContentManagerSession.cs" />
<Compile Include="FileSystems\WebSite\WebSiteFolder.cs" /> <Compile Include="FileSystems\WebSite\WebSiteFolder.cs" />
<Compile Include="FileSystems\AppData\IAppDataFolder.cs" /> <Compile Include="FileSystems\AppData\IAppDataFolder.cs" />
<Compile Include="FileSystems\WebSite\IWebSiteFolder.cs" /> <Compile Include="FileSystems\WebSite\IWebSiteFolder.cs" />