mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-21 03:14:10 +08:00
Removing unused methods and refactoring the batch loop
--HG-- branch : indexing
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Autofac;
|
||||
using Lucene.Services;
|
||||
using Moq;
|
||||
@@ -176,6 +175,7 @@ namespace Orchard.Tests.Modules.Indexing {
|
||||
|
||||
// there should be nothing done
|
||||
_indexNotifier.UpdateIndex(IndexName);
|
||||
Assert.That(_provider.NumDocs(IndexName), Is.EqualTo(1));
|
||||
|
||||
_contentManager.Create<Thing>(ThingDriver.ContentTypeName).Text = "Lorem ipsum";
|
||||
_indexNotifier.UpdateIndex(IndexName);
|
||||
@@ -216,6 +216,17 @@ namespace Orchard.Tests.Modules.Indexing {
|
||||
Assert.That(_provider.NumDocs(IndexName), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void ShouldIndexAllContentOverTheLoopSize() {
|
||||
for (int i = 0; i < 999; i++) {
|
||||
var content = _contentManager.Create<Thing>(ThingDriver.ContentTypeName);
|
||||
content.Text = "Lorem ipsum " + i;
|
||||
}
|
||||
_indexNotifier.UpdateIndex(IndexName);
|
||||
Assert.That(_provider.NumDocs(IndexName), Is.EqualTo(999));
|
||||
}
|
||||
|
||||
#region Stubs
|
||||
public class ThingHandler : ContentHandler {
|
||||
public ThingHandler() {
|
||||
|
@@ -50,7 +50,7 @@ namespace Orchard.Indexing.Models
|
||||
new XElement(TagMode, Mode),
|
||||
new XElement(TagLastIndexedId, LastIndexedId),
|
||||
new XElement(TagLastContentId, LastContentId),
|
||||
new XElement(TagLastIndexedUtc, LastIndexedUtc.ToString("s"))
|
||||
new XElement(TagLastIndexedUtc, LastIndexedUtc.ToString("u"))
|
||||
)).ToString();
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Data;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.FileSystems.AppData;
|
||||
@@ -22,7 +23,8 @@ namespace Orchard.Indexing.Services {
|
||||
/// </remarks>
|
||||
[UsedImplicitly]
|
||||
public class IndexingTaskExecutor : IIndexNotifierHandler, IIndexStatisticsProvider {
|
||||
private readonly IRepository<IndexingTaskRecord> _repository;
|
||||
private readonly IRepository<IndexingTaskRecord> _taskRepository;
|
||||
private readonly IRepository<ContentItemVersionRecord> _contentRepository;
|
||||
private IIndexProvider _indexProvider;
|
||||
private readonly IIndexManager _indexManager;
|
||||
private readonly IContentManager _contentManager;
|
||||
@@ -34,14 +36,16 @@ namespace Orchard.Indexing.Services {
|
||||
private IndexingStatus _indexingStatus = IndexingStatus.Idle;
|
||||
|
||||
public IndexingTaskExecutor(
|
||||
IRepository<IndexingTaskRecord> repository,
|
||||
IRepository<IndexingTaskRecord> taskRepository,
|
||||
IRepository<ContentItemVersionRecord> contentRepository,
|
||||
IIndexManager indexManager,
|
||||
IContentManager contentManager,
|
||||
IAppDataFolder appDataFolder,
|
||||
ShellSettings shellSettings,
|
||||
ILockFileManager lockFileManager,
|
||||
IClock clock) {
|
||||
_repository = repository;
|
||||
_taskRepository = taskRepository;
|
||||
_contentRepository = contentRepository;
|
||||
_indexManager = indexManager;
|
||||
_contentManager = contentManager;
|
||||
_appDataFolder = appDataFolder;
|
||||
@@ -54,6 +58,11 @@ namespace Orchard.Indexing.Services {
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public void UpdateIndex(string indexName) {
|
||||
// What to do here to run next batch in a separate transaction
|
||||
while (UpdateIndexBatch(indexName)) {}
|
||||
}
|
||||
|
||||
public bool UpdateIndexBatch(string indexName) {
|
||||
ILockFile lockFile = null;
|
||||
var settingsFilename = GetSettingsFileName(indexName);
|
||||
var lockFilename = settingsFilename + ".lock";
|
||||
@@ -61,13 +70,12 @@ namespace Orchard.Indexing.Services {
|
||||
// acquire a lock file on the index
|
||||
if (!_lockFileManager.TryAcquireLock(lockFilename, ref lockFile)) {
|
||||
Logger.Information("Index was requested but is already running");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
using (lockFile)
|
||||
{
|
||||
using (lockFile) {
|
||||
if (!_indexManager.HasIndexProvider()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// load index settings to know what is the current state of indexing
|
||||
@@ -79,10 +87,28 @@ namespace Orchard.Indexing.Services {
|
||||
if (!_indexProvider.Exists(indexName)) {
|
||||
_indexProvider.CreateIndex(indexName);
|
||||
indexSettings = new IndexSettings();
|
||||
|
||||
// mark the last available task at the moment the process is started.
|
||||
// once the Rebuild is done, Update will start at this point of the table
|
||||
indexSettings.LastIndexedId = _taskRepository
|
||||
.Table
|
||||
.OrderByDescending(x => x.Id)
|
||||
.Select(x => x.Id)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
// execute indexing commands by batch of [ContentItemsPerLoop] content items
|
||||
for (; ; ){
|
||||
return BatchIndex(indexName, settingsFilename, indexSettings);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indexes a batch of content items
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <c>true</c> if there are more items to process; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
private bool BatchIndex(string indexName, string settingsFilename, IndexSettings indexSettings) {
|
||||
var addToIndex = new List<IDocumentIndex>();
|
||||
var deleteFromIndex = new List<int>();
|
||||
|
||||
@@ -91,44 +117,33 @@ namespace Orchard.Indexing.Services {
|
||||
Logger.Information("Rebuilding index");
|
||||
_indexingStatus = IndexingStatus.Rebuilding;
|
||||
|
||||
// store the last inserted task
|
||||
var lastIndexId = _repository
|
||||
.Fetch(x => true)
|
||||
.OrderByDescending(x => x.Id)
|
||||
.Select(x => x.Id)
|
||||
.FirstOrDefault();
|
||||
|
||||
// load all content items
|
||||
var contentItemIds = _contentManager
|
||||
.Query(VersionOptions.Published)
|
||||
.List()
|
||||
.Where(x => x.Id > indexSettings.LastContentId)
|
||||
.OrderBy(x => x.Id)
|
||||
.Select(x => x.Id)
|
||||
.Distinct()
|
||||
var contentItems = _contentRepository
|
||||
.Fetch(
|
||||
versionRecord => versionRecord.Published && versionRecord.ContentItemRecord.Id > indexSettings.LastContentId,
|
||||
order => order.Asc(versionRecord => versionRecord.Id))
|
||||
.Take(ContentItemsPerLoop)
|
||||
.ToArray();
|
||||
|
||||
indexSettings.LastIndexedId = lastIndexId;
|
||||
.Select(versionRecord => _contentManager.Get(versionRecord.ContentItemRecord.Id, VersionOptions.VersionRecord(versionRecord.Id)))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
// if no more elements to index, switch to update mode
|
||||
if (contentItemIds.Length == 0) {
|
||||
if (contentItems.Count == 0) {
|
||||
indexSettings.Mode = IndexingMode.Update;
|
||||
}
|
||||
|
||||
foreach (var id in contentItemIds) {
|
||||
foreach (var item in contentItems) {
|
||||
try {
|
||||
IDocumentIndex documentIndex = ExtractDocumentIndex(id);
|
||||
IDocumentIndex documentIndex = ExtractDocumentIndex(item);
|
||||
|
||||
if (documentIndex != null && documentIndex.IsDirty) {
|
||||
addToIndex.Add(documentIndex);
|
||||
}
|
||||
|
||||
// store the last processed element
|
||||
indexSettings.LastContentId = contentItemIds.LastOrDefault();
|
||||
indexSettings.LastContentId = item.VersionRecord.Id;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Warning(ex, "Unable to index content item #{0} during rebuild", id);
|
||||
Logger.Warning(ex, "Unable to index content item #{0} during rebuild", item.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,36 +152,30 @@ namespace Orchard.Indexing.Services {
|
||||
Logger.Information("Updating index");
|
||||
_indexingStatus = IndexingStatus.Updating;
|
||||
|
||||
// load next content items to index, by filtering and ordering on the task id
|
||||
var lastIndexId = _repository
|
||||
.Fetch(x => x.Id > indexSettings.LastIndexedId)
|
||||
.OrderByDescending(x => x.Id)
|
||||
.Select(x => x.Id)
|
||||
.FirstOrDefault();
|
||||
|
||||
var contentItemIds = _repository
|
||||
var contentItems = _taskRepository
|
||||
.Fetch(x => x.Id > indexSettings.LastIndexedId)
|
||||
.OrderBy(x => x.Id)
|
||||
.Take(ContentItemsPerLoop)
|
||||
.Select(x => x.ContentItemRecord.Id)
|
||||
.Distinct() // don't process the same content item twice
|
||||
.GroupBy(x => x.ContentItemRecord.Id)
|
||||
.Select(group => new {TaskId = group.Max(task => task.Id), ContentItem = _contentManager.Get(group.Key, VersionOptions.Published)})
|
||||
.OrderBy(x => x.TaskId)
|
||||
.ToArray();
|
||||
|
||||
indexSettings.LastIndexedId = lastIndexId;
|
||||
|
||||
foreach (var id in contentItemIds) {
|
||||
foreach (var item in contentItems) {
|
||||
try {
|
||||
IDocumentIndex documentIndex = ExtractDocumentIndex(id);
|
||||
IDocumentIndex documentIndex = ExtractDocumentIndex(item.ContentItem);
|
||||
|
||||
if (documentIndex == null) {
|
||||
deleteFromIndex.Add(id);
|
||||
deleteFromIndex.Add(item.ContentItem.Id);
|
||||
}
|
||||
else if (documentIndex.IsDirty) {
|
||||
addToIndex.Add(documentIndex);
|
||||
}
|
||||
|
||||
indexSettings.LastIndexedId = item.TaskId;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Logger.Warning(ex, "Unable to index content item #{0} during rebuild", id);
|
||||
Logger.Warning(ex, "Unable to index content item #{0} during update", item.ContentItem.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,7 +187,7 @@ namespace Orchard.Indexing.Services {
|
||||
if (deleteFromIndex.Count == 0 && addToIndex.Count == 0) {
|
||||
// nothing more to do
|
||||
_indexingStatus = IndexingStatus.Idle;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// save new and updated documents to the index
|
||||
@@ -202,8 +211,8 @@ namespace Orchard.Indexing.Services {
|
||||
catch (Exception ex) {
|
||||
Logger.Warning(ex, "An error occured while removing a document from the index");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -224,9 +233,7 @@ namespace Orchard.Indexing.Services {
|
||||
/// Creates a IDocumentIndex instance for a specific content item id. If the content
|
||||
/// item is no more published, it returns null.
|
||||
/// </summary>
|
||||
private IDocumentIndex ExtractDocumentIndex(int id) {
|
||||
var contentItem = _contentManager.Get(id, VersionOptions.Published);
|
||||
|
||||
private IDocumentIndex ExtractDocumentIndex(ContentItem contentItem) {
|
||||
// ignore deleted or unpublished items
|
||||
if (contentItem == null || !contentItem.IsPublished()) {
|
||||
return null;
|
||||
@@ -234,8 +241,9 @@ namespace Orchard.Indexing.Services {
|
||||
|
||||
// skip items from types which are not indexed
|
||||
var settings = GetTypeIndexingSettings(contentItem);
|
||||
if (!settings.Included)
|
||||
if (!settings.Included) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var documentIndex = _indexProvider.New(contentItem.Id);
|
||||
|
||||
@@ -244,7 +252,7 @@ namespace Orchard.Indexing.Services {
|
||||
return documentIndex;
|
||||
}
|
||||
|
||||
static TypeIndexing GetTypeIndexingSettings(ContentItem contentItem) {
|
||||
private static TypeIndexing GetTypeIndexingSettings(ContentItem contentItem) {
|
||||
if (contentItem == null ||
|
||||
contentItem.TypeDefinition == null ||
|
||||
contentItem.TypeDefinition.Settings == null) {
|
||||
|
@@ -51,9 +51,5 @@ namespace Orchard.Indexing.Services {
|
||||
CreateTask(contentItem, IndexingTaskRecord.Delete);
|
||||
Logger.Information("Deleting index task created for [{0}:{1}]", contentItem.ContentType, contentItem.Id);
|
||||
}
|
||||
|
||||
public DateTime GetLastTaskDateTime() {
|
||||
return _repository.Table.Max(t => t.CreatedUtc) ?? new DateTime(1980, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -12,10 +12,5 @@ namespace Orchard.Tasks.Indexing {
|
||||
/// Adds a new entry in the index task table in order to delete an existing index for the specified content item.
|
||||
/// </summary>
|
||||
void CreateDeleteIndexTask(ContentItem contentItem);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Date Time of the last task created
|
||||
/// </summary>
|
||||
DateTime GetLastTaskDateTime();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user