2010-06-02 15:56:54 -07:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using JetBrains.Annotations ;
using Orchard.ContentManagement ;
using Orchard.Data ;
2011-03-03 14:19:02 -08:00
using Orchard.Environment.Configuration ;
using Orchard.FileSystems.AppData ;
using Orchard.FileSystems.LockFile ;
2010-06-17 16:21:29 -07:00
using Orchard.Indexing.Models ;
2010-06-30 12:38:21 -07:00
using Orchard.Indexing.Settings ;
2010-06-02 15:56:54 -07:00
using Orchard.Logging ;
using Orchard.Services ;
2010-06-04 17:42:20 -07:00
using Orchard.Tasks.Indexing ;
2010-06-02 15:56:54 -07:00
2010-06-17 16:21:29 -07:00
namespace Orchard.Indexing.Services {
2010-06-02 15:56:54 -07:00
/// <summary>
/// Contains the logic which is regularly executed to retrieve index information from multiple content handlers.
/// </summary>
2011-03-03 14:19:02 -08:00
/// <remarks>
/// This class is synchronized using a lock file as both command line and web workers can potentially use it,
/// and singleton locks would not be shared accross those two.
/// </remarks>
2010-06-02 15:56:54 -07:00
[UsedImplicitly]
2010-06-17 16:21:29 -07:00
public class IndexingTaskExecutor : IIndexNotifierHandler {
2010-06-02 15:56:54 -07:00
private readonly IClock _clock ;
private readonly IRepository < IndexingTaskRecord > _repository ;
private IIndexProvider _indexProvider ;
2010-06-03 13:12:07 -07:00
private readonly IIndexManager _indexManager ;
2010-06-04 17:42:20 -07:00
private readonly IIndexingTaskManager _indexingTaskManager ;
2010-06-02 15:56:54 -07:00
private readonly IContentManager _contentManager ;
2011-03-03 14:19:02 -08:00
private readonly IAppDataFolder _appDataFolder ;
private readonly ShellSettings _shellSettings ;
private readonly ILockFileManager _lockFileManager ;
2010-06-30 12:38:21 -07:00
2010-06-02 15:56:54 -07:00
public IndexingTaskExecutor (
IClock clock ,
IRepository < IndexingTaskRecord > repository ,
IIndexManager indexManager ,
2010-06-04 17:42:20 -07:00
IIndexingTaskManager indexingTaskManager ,
2010-06-17 16:21:29 -07:00
IContentManager contentManager ,
2011-03-03 14:19:02 -08:00
IAppDataFolder appDataFolder ,
ShellSettings shellSettings ,
ILockFileManager lockFileManager ) {
2010-06-02 15:56:54 -07:00
_clock = clock ;
_repository = repository ;
_indexManager = indexManager ;
2010-06-04 17:42:20 -07:00
_indexingTaskManager = indexingTaskManager ;
2010-06-02 15:56:54 -07:00
_contentManager = contentManager ;
2011-03-03 14:19:02 -08:00
_appDataFolder = appDataFolder ;
_shellSettings = shellSettings ;
_lockFileManager = lockFileManager ;
2010-06-02 15:56:54 -07:00
Logger = NullLogger . Instance ;
}
public ILogger Logger { get ; set ; }
2010-06-04 17:42:20 -07:00
public void UpdateIndex ( string indexName ) {
2011-03-03 14:19:02 -08:00
ILockFile lockFile = null ;
var settingsFilename = GetSettingsFileName ( indexName ) ;
var lockFilename = settingsFilename + ".lock" ;
2010-06-02 15:56:54 -07:00
2011-03-03 14:19:02 -08:00
if ( ! _lockFileManager . TryAcquireLock ( lockFilename , ref lockFile ) ) {
2010-06-04 17:42:20 -07:00
Logger . Information ( "Index was requested but was already running" ) ;
2010-06-02 15:56:54 -07:00
return ;
}
2011-03-03 14:19:02 -08:00
using ( lockFile ) {
2010-06-04 17:42:20 -07:00
if ( ! _indexManager . HasIndexProvider ( ) ) {
return ;
}
2010-06-02 15:56:54 -07:00
2010-06-04 17:42:20 -07:00
_indexProvider = _indexManager . GetSearchIndexProvider ( ) ;
2010-06-17 16:21:29 -07:00
var updateIndexDocuments = new List < IDocumentIndex > ( ) ;
2010-07-30 19:19:53 -07:00
var addedContentItemIds = new List < string > ( ) ;
2010-07-11 12:11:38 -07:00
DateTime ? lastIndexUtc ;
2010-06-04 17:42:20 -07:00
// Do we need to rebuild the full index (first time module is used, or rebuild index requested) ?
2011-02-24 16:58:18 -08:00
if ( _indexProvider . IsEmpty ( indexName ) ) {
2010-06-04 17:42:20 -07:00
Logger . Information ( "Rebuild index started" ) ;
// mark current last task, as we should process older ones (in case of rebuild index only)
2010-07-11 12:11:38 -07:00
lastIndexUtc = _indexingTaskManager . GetLastTaskDateTime ( ) ;
2010-06-04 17:42:20 -07:00
// get every existing content item to index it
foreach ( var contentItem in _contentManager . Query ( VersionOptions . Published ) . List ( ) ) {
try {
2010-06-30 12:38:21 -07:00
// skip items which are not indexed
var settings = GetTypeIndexingSettings ( contentItem ) ;
if ( ! settings . Included )
continue ;
var documentIndex = _indexProvider . New ( contentItem . Id ) ;
2010-06-04 17:42:20 -07:00
2010-06-17 16:21:29 -07:00
_contentManager . Index ( contentItem , documentIndex ) ;
2010-06-30 12:38:21 -07:00
if ( documentIndex . IsDirty ) {
2010-06-17 16:21:29 -07:00
updateIndexDocuments . Add ( documentIndex ) ;
2010-07-30 19:19:53 -07:00
addedContentItemIds . Add ( contentItem . Id . ToString ( ) ) ;
2010-06-04 17:42:20 -07:00
}
}
catch ( Exception ex ) {
Logger . Warning ( ex , "Unable to index content item #{0} during rebuild" , contentItem . Id ) ;
}
}
2010-06-03 13:12:07 -07:00
2010-06-04 17:42:20 -07:00
}
else {
// retrieve last processed index time
2011-02-24 16:58:18 -08:00
lastIndexUtc = _indexProvider . GetLastIndexUtc ( indexName ) ;
2010-06-04 17:42:20 -07:00
}
2010-06-02 15:56:54 -07:00
2011-02-24 16:58:18 -08:00
_indexProvider . SetLastIndexUtc ( indexName , _clock . UtcNow ) ;
2010-06-02 15:56:54 -07:00
2010-06-04 17:42:20 -07:00
// retrieve not yet processed tasks
2010-07-11 12:11:38 -07:00
var taskRecords = lastIndexUtc = = null
2011-03-03 14:19:02 -08:00
? _repository . Fetch ( x = > true ) . ToArray ( )
: _repository . Fetch ( x = > x . CreatedUtc > = lastIndexUtc ) . ToArray ( ) ; // CreatedUtc and lastIndexUtc might be equal if a content item is created in a background task
2010-06-30 12:38:21 -07:00
2011-01-07 15:51:10 -08:00
// nothing to do ?)))
2010-07-29 15:44:15 -07:00
if ( taskRecords . Length + updateIndexDocuments . Count = = 0 ) {
Logger . Information ( "Index update requested, nothing to do" ) ;
2010-06-04 17:42:20 -07:00
return ;
2010-07-29 15:44:15 -07:00
}
2010-06-03 13:12:07 -07:00
2010-06-04 17:42:20 -07:00
Logger . Information ( "Processing {0} indexing tasks" , taskRecords . Length ) ;
2010-06-03 13:12:07 -07:00
2011-02-24 16:58:18 -08:00
if ( ! _indexProvider . Exists ( indexName ) ) {
_indexProvider . CreateIndex ( indexName ) ;
2010-06-04 17:42:20 -07:00
}
2010-06-02 15:56:54 -07:00
2010-06-04 17:42:20 -07:00
// process Delete tasks
2010-06-02 15:56:54 -07:00
try {
2010-07-30 19:19:53 -07:00
var deleteIds = taskRecords . Where ( t = > t . Action = = IndexingTaskRecord . Delete ) . Select ( t = > t . ContentItemRecord . Id ) . ToArray ( ) ;
if ( deleteIds . Length > 0 ) {
2011-02-24 16:58:18 -08:00
_indexProvider . Delete ( indexName , deleteIds ) ;
2010-07-30 19:19:53 -07:00
Logger . Information ( "Deleted content items from index: {0}" , String . Join ( ", " , deleteIds ) ) ;
}
2010-06-02 15:56:54 -07:00
}
2010-06-04 16:29:50 -07:00
catch ( Exception ex ) {
2010-06-04 17:42:20 -07:00
Logger . Warning ( ex , "An error occured while removing a document from the index" ) ;
2010-06-02 15:56:54 -07:00
}
2010-06-04 17:42:20 -07:00
// process Update tasks
foreach ( var taskRecord in taskRecords . Where ( t = > t . Action = = IndexingTaskRecord . Update ) ) {
var task = new IndexingTask ( _contentManager , taskRecord ) ;
2010-06-30 12:38:21 -07:00
// skip items which are not indexed
var settings = GetTypeIndexingSettings ( task . ContentItem ) ;
if ( ! settings . Included )
continue ;
2010-06-04 17:42:20 -07:00
try {
2010-06-17 16:21:29 -07:00
var documentIndex = _indexProvider . New ( task . ContentItem . Id ) ;
_contentManager . Index ( task . ContentItem , documentIndex ) ;
2011-01-07 18:57:39 -08:00
if ( ! addedContentItemIds . Contains ( task . ContentItem . Id . ToString ( ) ) & & documentIndex . IsDirty ) {
2010-06-17 16:21:29 -07:00
updateIndexDocuments . Add ( documentIndex ) ;
2010-06-04 17:42:20 -07:00
}
2010-06-08 11:42:32 -07:00
2010-06-04 17:42:20 -07:00
}
catch ( Exception ex ) {
Logger . Warning ( ex , "Unable to process indexing task #{0}" , taskRecord . Id ) ;
}
2010-06-03 13:12:07 -07:00
}
2010-06-04 17:42:20 -07:00
if ( updateIndexDocuments . Count > 0 ) {
try {
2011-02-24 16:58:18 -08:00
_indexProvider . Store ( indexName , updateIndexDocuments ) ;
2010-07-30 19:19:53 -07:00
Logger . Information ( "Added content items to index: {0}" , String . Join ( ", " , addedContentItemIds ) ) ;
2010-06-04 17:42:20 -07:00
}
catch ( Exception ex ) {
Logger . Warning ( ex , "An error occured while adding a document to the index" ) ;
}
2010-06-04 16:29:50 -07:00
}
2010-06-03 13:12:07 -07:00
}
2010-06-02 15:56:54 -07:00
}
2010-06-30 12:38:21 -07:00
static TypeIndexing GetTypeIndexingSettings ( ContentItem contentItem ) {
if ( contentItem = = null | |
contentItem . TypeDefinition = = null | |
contentItem . TypeDefinition . Settings = = null ) {
return new TypeIndexing { Included = false } ;
}
return contentItem . TypeDefinition . Settings . GetModel < TypeIndexing > ( ) ;
}
2011-03-03 14:19:02 -08:00
private string GetSettingsFileName ( string indexName ) {
return _appDataFolder . Combine ( "Sites" , _shellSettings . Name , indexName + ".settings.xml" ) ;
}
2010-06-02 15:56:54 -07:00
}
}