diff --git a/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj b/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj index 2f2bb5866d..454a6cf2ce 100644 --- a/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj +++ b/src/SQLCE4Umbraco/SqlCE4Umbraco.csproj @@ -49,11 +49,9 @@ ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll - True ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll - True diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 340a7ae6d8..e52720b574 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -39,22 +39,18 @@ ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll - True ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll - True ..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll ..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll - True ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll - True ..\packages\ImageProcessor.2.5.6\lib\net45\ImageProcessor.dll @@ -67,11 +63,9 @@ ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll - True ..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll - True ..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll @@ -87,17 +81,16 @@ ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll - True ..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll + True ..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll ..\packages\Owin.1.0\lib\net40\Owin.dll - True ..\packages\semver.1.1.2\lib\net45\Semver.dll @@ -109,11 +102,9 @@ ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll - True ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll - True diff --git a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj index 64fef90ffa..6cad6893f5 100644 --- a/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj +++ b/src/Umbraco.Tests.Benchmarks/Umbraco.Tests.Benchmarks.csproj @@ -40,34 +40,27 @@ ..\packages\BenchmarkDotNet.0.9.9\lib\net45\BenchmarkDotNet.dll - True ..\packages\BenchmarkDotNet.Core.0.9.9\lib\net45\BenchmarkDotNet.Core.dll - True ..\packages\BenchmarkDotNet.Diagnostics.Windows.0.9.9\lib\net45\BenchmarkDotNet.Diagnostics.Windows.dll - True ..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.9.9\lib\net45\BenchmarkDotNet.Toolchains.Roslyn.dll - True ..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll ..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll - True ..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll - True ..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\lib\net40\Microsoft.Diagnostics.Tracing.TraceEvent.dll - True ..\packages\Moq.4.1.1309.0919\lib\net40\Moq.dll @@ -75,27 +68,22 @@ ..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - True ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll - True ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll - True ..\packages\System.Reflection.Metadata.1.3.0\lib\portable-net45+win8\System.Reflection.Metadata.dll - True ..\packages\System.Threading.Tasks.Extensions.4.0.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll - True @@ -116,6 +104,7 @@ + @@ -132,8 +121,8 @@ - - + + diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 3fd09fc532..935731f00a 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -62,8 +62,8 @@ ..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll - - ..\packages\Examine.0.1.88\lib\net45\Examine.dll + + ..\packages\Examine.0.1.89-beta05\lib\net45\Examine.dll ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll diff --git a/src/Umbraco.Tests/packages.config b/src/Umbraco.Tests/packages.config index 921ac155c7..6075f6da6d 100644 --- a/src/Umbraco.Tests/packages.config +++ b/src/Umbraco.Tests/packages.config @@ -2,7 +2,7 @@ - + diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index bfca512100..9bad128cc6 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -127,11 +127,10 @@ ..\packages\dotless.1.5.2\lib\dotless.Core.dll - - ..\packages\Examine.0.1.88\lib\net45\Examine.dll + + ..\packages\Examine.0.1.89-beta05\lib\net45\Examine.dll - False ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll @@ -144,7 +143,6 @@ ..\packages\log4net.2.0.8\lib\net45-full\log4net.dll - False ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll diff --git a/src/Umbraco.Web.UI/packages.config b/src/Umbraco.Web.UI/packages.config index a17f6414ed..a87caf5199 100644 --- a/src/Umbraco.Web.UI/packages.config +++ b/src/Umbraco.Web.UI/packages.config @@ -4,7 +4,7 @@ - + diff --git a/src/Umbraco.Web/ExamineStartup.cs b/src/Umbraco.Web/ExamineStartup.cs new file mode 100644 index 0000000000..c8cc83663c --- /dev/null +++ b/src/Umbraco.Web/ExamineStartup.cs @@ -0,0 +1,175 @@ +using System.Collections.Generic; +using System.Linq; +using Examine; +using Examine.Config; +using Examine.LuceneEngine; +using Examine.LuceneEngine.Providers; +using Examine.Providers; +using Lucene.Net.Index; +using Lucene.Net.Store; +using Umbraco.Core; +using Umbraco.Core.Logging; +using UmbracoExamine; + +namespace Umbraco.Web +{ + /// + /// Used to configure Examine during startup for the web application + /// + internal class ExamineStartup + { + private readonly List _indexesToRebuild = new List(); + private readonly ApplicationContext _appCtx; + private readonly ProfilingLogger _profilingLogger; + + //this is used if we are not the MainDom, in which case we need to ensure that if indexes need rebuilding that this + //doesn't occur since that should only occur when we are MainDom + private bool _disableExamineIndexing = false; + + public ExamineStartup(ApplicationContext appCtx) + { + _appCtx = appCtx; + _profilingLogger = appCtx.ProfilingLogger; + } + + /// + /// Called during the initialize operation of the boot manager process + /// + public void Initialize() + { + //We want to manage Examine's appdomain shutdown sequence ourselves so first we'll disable Examine's default behavior + //and then we'll use MainDom to control Examine's shutdown + ExamineManager.DisableDefaultHostingEnvironmentRegistration(); + + //we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the appdomain + //terminates and in some rare cases would only allow unlocking of the file if IIS is forcefully terminated. Instead we'll rely on the simplefslock + //which simply checks the existence of the lock file + DirectoryTracker.DefaultLockFactory = d => + { + var simpleFsLockFactory = new NoPrefixSimpleFsLockFactory(d); + return simpleFsLockFactory; + }; + + //This is basically a hack for this item: http://issues.umbraco.org/issue/U4-5976 + // when Examine initializes it will try to rebuild if the indexes are empty, however in many cases not all of Examine's + // event handlers will be assigned during bootup when the rebuilding starts which is a problem. So with the examine 0.1.58.2941 build + // it has an event we can subscribe to in order to cancel this rebuilding process, but what we'll do is cancel it and postpone the rebuilding until the + // boot process has completed. It's a hack but it works. + ExamineManager.Instance.BuildingEmptyIndexOnStartup += OnInstanceOnBuildingEmptyIndexOnStartup; + + //let's deal with shutting down Examine with MainDom + var examineShutdownRegistered = _appCtx.MainDom.Register(() => + { + using (_profilingLogger.TraceDuration("Examine shutting down")) + { + //Due to the way Examine's own IRegisteredObject works, we'll first run it with immediate=false and then true so that + //it's correct subroutines are executed (otherwise we'd have to run this logic manually ourselves) + ExamineManager.Instance.Stop(false); + ExamineManager.Instance.Stop(true); + } + }); + if (examineShutdownRegistered) + { + _profilingLogger.Logger.Debug("Examine shutdown registered with MainDom"); + } + else + { + _profilingLogger.Logger.Debug("Examine shutdown not registered, this appdomain is not the MainDom"); + + //if we could not register the shutdown examine ourselves, it means we are not maindom! in this case all of examine should be disabled + //from indexing anything on startup!! + _disableExamineIndexing = true; + } + } + + /// + /// Called during the Complete operation of the boot manager process + /// + public void Complete() + { + //We now need to disable waiting for indexing for Examine so that the appdomain is shutdown immediately and doesn't wait for pending + //indexing operations. We used to wait for indexing operations to complete but this can cause more problems than that is worth because + //that could end up halting shutdown for a very long time causing overlapping appdomains and many other problems. + foreach (var luceneIndexer in ExamineManager.Instance.IndexProviderCollection.OfType()) + { + luceneIndexer.WaitForIndexQueueOnShutdown = false; + } + + //Ok, now that everything is complete we'll check if we've stored any references to index that need rebuilding and run them + // (see the initialize method for notes) - we'll ensure we remove the event handler too in case examine manager doesn't actually + // initialize during startup, in which case we want it to rebuild the indexes itself. + ExamineManager.Instance.BuildingEmptyIndexOnStartup -= OnInstanceOnBuildingEmptyIndexOnStartup; + + //don't do anything if we have disabled this + if (_disableExamineIndexing == false) + { + foreach (var indexer in _indexesToRebuild) + { + indexer.RebuildIndex(); + } + } + } + + /// + /// Called to perform the rebuilding indexes on startup if the indexes don't exist + /// + public void RebuildIndexes() + { + //don't do anything if we have disabled this + if (_disableExamineIndexing) return; + + //If the developer has explicitly opted out of rebuilding indexes on startup then we + // should adhere to that and not do it, this means that if they are load balancing things will be + // out of sync if they are auto-scaling but there's not much we can do about that. + if (ExamineSettings.Instance.RebuildOnAppStart == false) return; + + foreach (var indexer in GetIndexesForColdBoot()) + { + indexer.RebuildIndex(); + } + } + + /// + /// The method used to create indexes on a cold boot + /// + /// + /// A cold boot is when the server determines it will not (or cannot) process instructions in the cache table and + /// will rebuild it's own caches itself. + /// + public IEnumerable GetIndexesForColdBoot() + { + // NOTE: This is IMPORTANT! ... we don't want to rebuild any index that is already flagged to be re-indexed + // on startup based on our _indexesToRebuild variable and how Examine auto-rebuilds when indexes are empty. + // This callback is used above for the DatabaseServerMessenger startup options. + + // all indexes + IEnumerable indexes = ExamineManager.Instance.IndexProviderCollection; + + // except those that are already flagged + // and are processed in Complete() + if (_indexesToRebuild.Any()) + indexes = indexes.Except(_indexesToRebuild); + + // return + foreach (var index in indexes) + yield return index; + } + + private void OnInstanceOnBuildingEmptyIndexOnStartup(object sender, BuildingEmptyIndexOnStartupEventArgs args) + { + //store the indexer that needs rebuilding because it's empty for when the boot process + // is complete and cancel this current event so the rebuild process doesn't start right now. + args.Cancel = true; + _indexesToRebuild.Add((BaseIndexProvider)args.Indexer); + + //check if the index is rebuilding due to an error and log it + if (args.IsHealthy == false) + { + var baseIndex = args.Indexer as BaseIndexProvider; + var name = baseIndex != null ? baseIndex.Name : "[UKNOWN]"; + + _profilingLogger.Logger.Error(string.Format("The index {0} is rebuilding due to being unreadable/corrupt", name), args.UnhealthyException); + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index aa54d7b369..b3fb40608e 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -112,8 +112,8 @@ ..\packages\dotless.1.5.2\lib\dotless.Core.dll - - ..\packages\Examine.0.1.88\lib\net45\Examine.dll + + ..\packages\Examine.0.1.89-beta05\lib\net45\Examine.dll ..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll @@ -121,11 +121,9 @@ ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll - True ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll - True ..\packages\Markdown.1.14.7\lib\net45\MarkdownSharp.dll @@ -333,6 +331,7 @@ + diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs index 2f6b81820f..c38540b6a2 100644 --- a/src/Umbraco.Web/WebBootManager.cs +++ b/src/Umbraco.Web/WebBootManager.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.Configuration; using System.Linq; -using System.Reflection; using System.Web; using System.Web.Configuration; using System.Web.Http; @@ -11,10 +10,7 @@ using System.Web.Http.Dispatcher; using System.Web.Mvc; using System.Web.Routing; using ClientDependency.Core.Config; -using Examine; -using Examine.Config; using Examine.Providers; -using umbraco; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Dictionary; @@ -27,25 +23,18 @@ using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Core.Sync; using Umbraco.Web.Dictionary; using Umbraco.Web.Install; -using Umbraco.Web.Macros; using Umbraco.Web.Media; using Umbraco.Web.Media.ThumbnailProviders; -using Umbraco.Web.Models; using Umbraco.Web.Mvc; -using Umbraco.Web.PropertyEditors; -using Umbraco.Web.PropertyEditors.ValueConverters; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; using Umbraco.Web.Security; -using Umbraco.Web.Scheduling; using Umbraco.Web.UI.JavaScript; using Umbraco.Web.WebApi; -using umbraco.BusinessLogic; using Umbraco.Core.Cache; using Umbraco.Core.Events; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.UnitOfWork; -using Umbraco.Core.Publishing; using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Web.Editors; @@ -64,8 +53,9 @@ namespace Umbraco.Web public class WebBootManager : CoreBootManager { private readonly bool _isForTesting; - //NOTE: see the Initialize method for what this is used for - private static readonly List IndexesToRebuild = new List(); + + //needs to be static because we have the public static method GetIndexesForColdBoot + private static ExamineStartup _examineStartup; public WebBootManager(UmbracoApplicationBase umbracoApplication) : base(umbracoApplication) @@ -109,15 +99,11 @@ namespace Umbraco.Web /// public override IBootManager Initialize() { - //This is basically a hack for this item: http://issues.umbraco.org/issue/U4-5976 - // when Examine initializes it will try to rebuild if the indexes are empty, however in many cases not all of Examine's - // event handlers will be assigned during bootup when the rebuilding starts which is a problem. So with the examine 0.1.58.2941 build - // it has an event we can subscribe to in order to cancel this rebuilding process, but what we'll do is cancel it and postpone the rebuilding until the - // boot process has completed. It's a hack but it works. - ExamineManager.Instance.BuildingEmptyIndexOnStartup += OnInstanceOnBuildingEmptyIndexOnStartup; - base.Initialize(); + _examineStartup = new ExamineStartup(ApplicationContext); + _examineStartup.Initialize(); + // Backwards compatibility - set the path and URL type for ClientDependency 1.5.1 [LK] ClientDependency.Core.CompositeFiles.Providers.XmlFileMapper.FileMapVirtualFolder = "~/App_Data/TEMP/ClientDependency"; ClientDependency.Core.CompositeFiles.Providers.BaseCompositeFileProcessingProvider.UrlTypeDefault = ClientDependency.Core.CompositeFiles.Providers.CompositeUrlType.Base64QueryStrings; @@ -214,25 +200,15 @@ namespace Umbraco.Web //Now, startup all of our legacy startup handler ApplicationEventsResolver.Current.InstantiateLegacyStartupHandlers(); - //Ok, now that everything is complete we'll check if we've stored any references to index that need rebuilding and run them - // (see the initialize method for notes) - we'll ensure we remove the event handler too in case examine manager doesn't actually - // initialize during startup, in which case we want it to rebuild the indexes itself. - ExamineManager.Instance.BuildingEmptyIndexOnStartup -= OnInstanceOnBuildingEmptyIndexOnStartup; - if (IndexesToRebuild.Any()) - { - foreach (var indexer in IndexesToRebuild) - { - indexer.RebuildIndex(); - } - } + _examineStartup.Complete(); //Now ensure webapi is initialized after everything GlobalConfiguration.Configuration.EnsureInitialized(); - + return this; } - + internal static void ConfigureGlobalFilters() { @@ -377,11 +353,11 @@ namespace Umbraco.Web { base.InitializeResolvers(); - SearchableTreeResolver.Current = new SearchableTreeResolver(ServiceProvider, LoggerResolver.Current.Logger, ApplicationContext.Services.ApplicationTreeService, () => PluginManager.ResolveSearchableTrees()); + SearchableTreeResolver.Current = new SearchableTreeResolver(ServiceProvider, LoggerResolver.Current.Logger, ApplicationContext.Services.ApplicationTreeService, () => PluginManager.ResolveSearchableTrees()); XsltExtensionsResolver.Current = new XsltExtensionsResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveXsltExtensions()); - EditorValidationResolver.Current= new EditorValidationResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveTypes()); + EditorValidationResolver.Current = new EditorValidationResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveTypes()); //set the default RenderMvcController DefaultRenderMvcControllerResolver.Current = new DefaultRenderMvcControllerResolver(typeof(RenderMvcController)); @@ -421,23 +397,6 @@ namespace Umbraco.Web } else { - - //We are using a custom action here so we can check the examine settings value first, we don't want to - // put that check into the CreateIndexesOnColdBoot method because developers may choose to use this - // method directly and they will be in charge of this check if they need it - Action rebuildIndexes = () => - { - //If the developer has explicitly opted out of rebuilding indexes on startup then we - // should adhere to that and not do it, this means that if they are load balancing things will be - // out of sync if they are auto-scaling but there's not much we can do about that. - if (ExamineSettings.Instance.RebuildOnAppStart == false) return; - - foreach (var indexer in GetIndexesForColdBoot()) - { - indexer.RebuildIndex(); - } - }; - ServerMessengerResolver.Current.SetServerMessenger(new BatchedDatabaseServerMessenger( ApplicationContext, true, @@ -453,7 +412,7 @@ namespace Umbraco.Web //rebuild indexes if the server is not synced // NOTE: This will rebuild ALL indexes including the members, if developers want to target specific // indexes then they can adjust this logic themselves. - rebuildIndexes + () => _examineStartup.RebuildIndexes() } })); } @@ -489,9 +448,9 @@ namespace Umbraco.Web // add all known factories, devs can then modify this list on application // startup either by binding to events or in their own global.asax new[] - { - typeof (RenderControllerFactory) - }); + { + typeof (RenderControllerFactory) + }); UrlProviderResolver.Current = new UrlProviderResolver( ServiceProvider, LoggerResolver.Current.Logger, @@ -559,42 +518,11 @@ namespace Umbraco.Web /// /// A cold boot is when the server determines it will not (or cannot) process instructions in the cache table and /// will rebuild it's own caches itself. + /// TODO: Does this method need to exist? Is it used publicly elsewhere (i.e. outside of core?) /// public static IEnumerable GetIndexesForColdBoot() { - // NOTE: This is IMPORTANT! ... we don't want to rebuild any index that is already flagged to be re-indexed - // on startup based on our _indexesToRebuild variable and how Examine auto-rebuilds when indexes are empty. - // This callback is used above for the DatabaseServerMessenger startup options. - - // all indexes - IEnumerable indexes = ExamineManager.Instance.IndexProviderCollection; - - // except those that are already flagged - // and are processed in Complete() - if (IndexesToRebuild.Any()) - indexes = indexes.Except(IndexesToRebuild); - - // return - foreach (var index in indexes) - yield return index; - } - - - private void OnInstanceOnBuildingEmptyIndexOnStartup(object sender, BuildingEmptyIndexOnStartupEventArgs args) - { - //store the indexer that needs rebuilding because it's empty for when the boot process - // is complete and cancel this current event so the rebuild process doesn't start right now. - args.Cancel = true; - IndexesToRebuild.Add((BaseIndexProvider)args.Indexer); - - //check if the index is rebuilding due to an error and log it - if (args.IsHealthy == false) - { - var baseIndex = args.Indexer as BaseIndexProvider; - var name = baseIndex != null ? baseIndex.Name : "[UKNOWN]"; - - ProfilingLogger.Logger.Error(string.Format("The index {0} is rebuilding due to being unreadable/corrupt", name), args.UnhealthyException); - } + return _examineStartup.GetIndexesForColdBoot(); } } } diff --git a/src/Umbraco.Web/WebServices/ExamineManagementApiController.cs b/src/Umbraco.Web/WebServices/ExamineManagementApiController.cs index ca49f7a9f7..1218ddc2da 100644 --- a/src/Umbraco.Web/WebServices/ExamineManagementApiController.cs +++ b/src/Umbraco.Web/WebServices/ExamineManagementApiController.cs @@ -8,7 +8,9 @@ using Examine; using Examine.LuceneEngine; using Examine.LuceneEngine.Providers; using Examine.Providers; +using Lucene.Net.Index; using Lucene.Net.Search; +using Lucene.Net.Store; using Umbraco.Core; using Umbraco.Core.Logging; using Umbraco.Web.Search; @@ -189,20 +191,39 @@ namespace Umbraco.Web.WebServices { indexer.RebuildIndex(); } + catch (LockObtainFailedException) + { + //this will occur if the index is locked (which it should defo not be!) so in this case we'll forcibly unlock it and try again + + try + { + IndexWriter.Unlock(indexer.GetLuceneDirectory()); + indexer.RebuildIndex(); + } + catch (Exception e) + { + return HandleException(e, indexer); + } + } catch (Exception ex) { - //ensure it's not listening - indexer.IndexOperationComplete -= Indexer_IndexOperationComplete; - LogHelper.Error("An error occurred rebuilding index", ex); - var response = Request.CreateResponse(HttpStatusCode.Conflict); - response.Content = new StringContent(string.Format("The index could not be rebuilt at this time, most likely there is another thread currently writing to the index. Error: {0}", ex)); - response.ReasonPhrase = "Could Not Rebuild"; - return response; + return HandleException(ex, indexer); } } return msg; } + private HttpResponseMessage HandleException(Exception ex, LuceneIndexer indexer) + { + //ensure it's not listening + indexer.IndexOperationComplete -= Indexer_IndexOperationComplete; + LogHelper.Error("An error occurred rebuilding index", ex); + var response = Request.CreateResponse(HttpStatusCode.Conflict); + response.Content = new StringContent(string.Format("The index could not be rebuilt at this time, most likely there is another thread currently writing to the index. Error: {0}", ex)); + response.ReasonPhrase = "Could Not Rebuild"; + return response; + } + //static listener so it's not GC'd private static void Indexer_IndexOperationComplete(object sender, EventArgs e) { diff --git a/src/Umbraco.Web/packages.config b/src/Umbraco.Web/packages.config index 905b005fe4..689b56c87e 100644 --- a/src/Umbraco.Web/packages.config +++ b/src/Umbraco.Web/packages.config @@ -3,7 +3,7 @@ - + diff --git a/src/UmbracoExamine/NoPrefixSimpleFsLockFactory.cs b/src/UmbracoExamine/NoPrefixSimpleFsLockFactory.cs new file mode 100644 index 0000000000..ac4210bcc0 --- /dev/null +++ b/src/UmbracoExamine/NoPrefixSimpleFsLockFactory.cs @@ -0,0 +1,26 @@ +using System.IO; +using Examine; +using Examine.LuceneEngine; +using Lucene.Net.Store; + +namespace UmbracoExamine +{ + /// + /// A custom that ensures a prefixless lock prefix + /// + /// + /// This is a work around for the Lucene APIs. By default Lucene will use a null prefix however when we set a custom + /// lock factory the null prefix is overwritten. + /// + public class NoPrefixSimpleFsLockFactory : SimpleFSLockFactory + { + public NoPrefixSimpleFsLockFactory(DirectoryInfo lockDir) : base(lockDir) + { + } + + public override void SetLockPrefix(string lockPrefix) + { + base.SetLockPrefix(null); + } + } +} \ No newline at end of file diff --git a/src/UmbracoExamine/UmbracoContentIndexer.cs b/src/UmbracoExamine/UmbracoContentIndexer.cs index 2a2e2ce98c..649c18df47 100644 --- a/src/UmbracoExamine/UmbracoContentIndexer.cs +++ b/src/UmbracoExamine/UmbracoContentIndexer.cs @@ -410,7 +410,11 @@ namespace UmbracoExamine { if (SupportedTypes.Contains(type) == false) return; - + + //if the app is shutting down do not continue + if (IsCancellationRequested) + return; + var pageIndex = 0; DataService.LogService.AddInfoLog(-1, string.Format("PerformIndexAll - Start data queries - {0}", type)); @@ -530,7 +534,7 @@ namespace UmbracoExamine content, notPublished).WhereNotNull(), type); pageIndex++; - } while (currentPageSize == PageSize); + } while (currentPageSize == PageSize && IsCancellationRequested == false); //do not continue if app is shutting down } break; @@ -628,7 +632,7 @@ namespace UmbracoExamine AddNodesToIndex(xElements, type); pageIndex++; - } while (more); + } while (more && IsCancellationRequested == false); //don't continue if the app is shutting down } internal static IEnumerable GetSerializedContent( diff --git a/src/UmbracoExamine/UmbracoExamine.csproj b/src/UmbracoExamine/UmbracoExamine.csproj index 015fc923cb..2c46c156ef 100644 --- a/src/UmbracoExamine/UmbracoExamine.csproj +++ b/src/UmbracoExamine/UmbracoExamine.csproj @@ -82,16 +82,14 @@ ..\Solution Items\TheFARM-Public.snk - - ..\packages\Examine.0.1.88\lib\net45\Examine.dll + + ..\packages\Examine.0.1.89-beta05\lib\net45\Examine.dll ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll - True ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll - True @@ -136,6 +134,7 @@ + diff --git a/src/UmbracoExamine/UmbracoMemberIndexer.cs b/src/UmbracoExamine/UmbracoMemberIndexer.cs index 8aa6a49d5a..f3ee7a4a89 100644 --- a/src/UmbracoExamine/UmbracoMemberIndexer.cs +++ b/src/UmbracoExamine/UmbracoMemberIndexer.cs @@ -197,7 +197,7 @@ namespace UmbracoExamine AddNodesToIndex(GetSerializedMembers(members), type); pageIndex++; - } while (members.Length == pageSize); + } while (members.Length == pageSize && IsCancellationRequested == false); //don't continue if the app is shutting down } } else @@ -211,7 +211,7 @@ namespace UmbracoExamine AddNodesToIndex(GetSerializedMembers(members), type); pageIndex++; - } while (members.Length == pageSize); + } while (members.Length == pageSize && IsCancellationRequested == false); //don't continue if the app is shutting down } } } diff --git a/src/UmbracoExamine/packages.config b/src/UmbracoExamine/packages.config index 40bdd28e84..74b8cbb907 100644 --- a/src/UmbracoExamine/packages.config +++ b/src/UmbracoExamine/packages.config @@ -1,6 +1,6 @@  - + \ No newline at end of file diff --git a/src/umbraco.MacroEngines/packages.config b/src/umbraco.MacroEngines/packages.config index 6aadcba8d4..14c21a4bd4 100644 --- a/src/umbraco.MacroEngines/packages.config +++ b/src/umbraco.MacroEngines/packages.config @@ -1,6 +1,6 @@  - + diff --git a/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj b/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj index d9734abfd8..bde18c31dd 100644 --- a/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj +++ b/src/umbraco.MacroEngines/umbraco.MacroEngines.csproj @@ -45,8 +45,8 @@ false - - ..\packages\Examine.0.1.88\lib\net45\Examine.dll + + ..\packages\Examine.0.1.89-beta05\lib\net45\Examine.dll ..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll @@ -54,11 +54,9 @@ ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll - True ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll - True ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll diff --git a/src/umbraco.businesslogic/umbraco.businesslogic.csproj b/src/umbraco.businesslogic/umbraco.businesslogic.csproj index bbc98ca0c7..cb1e47eaf8 100644 --- a/src/umbraco.businesslogic/umbraco.businesslogic.csproj +++ b/src/umbraco.businesslogic/umbraco.businesslogic.csproj @@ -108,11 +108,9 @@ ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll - True ..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll - True ..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll @@ -122,11 +120,9 @@ ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - True ..\packages\Owin.1.0\lib\net40\Owin.dll - True @@ -145,27 +141,21 @@ ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll - True ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll - True ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll - True ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll - True ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll - True ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll - True System.XML diff --git a/src/umbraco.cms/umbraco.cms.csproj b/src/umbraco.cms/umbraco.cms.csproj index 554cd0b969..e2baba7ada 100644 --- a/src/umbraco.cms/umbraco.cms.csproj +++ b/src/umbraco.cms/umbraco.cms.csproj @@ -108,15 +108,12 @@ ..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll - True ..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll - True ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll - True @@ -168,7 +165,6 @@ ..\packages\Tidy.Net.1.0.0\lib\TidyNet.dll - True diff --git a/src/umbraco.controls/umbraco.controls.csproj b/src/umbraco.controls/umbraco.controls.csproj index e458a56213..c562fa35d1 100644 --- a/src/umbraco.controls/umbraco.controls.csproj +++ b/src/umbraco.controls/umbraco.controls.csproj @@ -70,7 +70,6 @@ ..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll - True diff --git a/src/umbraco.datalayer/umbraco.datalayer.csproj b/src/umbraco.datalayer/umbraco.datalayer.csproj index e0fd450022..de34a0cfbb 100644 --- a/src/umbraco.datalayer/umbraco.datalayer.csproj +++ b/src/umbraco.datalayer/umbraco.datalayer.csproj @@ -70,10 +70,10 @@ ..\packages\Microsoft.ApplicationBlocks.Data.1.0.1559.20655\lib\Microsoft.ApplicationBlocks.Data.dll - True ..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll + True diff --git a/src/umbraco.editorControls/umbraco.editorControls.csproj b/src/umbraco.editorControls/umbraco.editorControls.csproj index 5950ac9719..602187e55a 100644 --- a/src/umbraco.editorControls/umbraco.editorControls.csproj +++ b/src/umbraco.editorControls/umbraco.editorControls.csproj @@ -116,7 +116,6 @@ ..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll - True System