From c765ab9112b4aaa54f1b0313223bc5a2bc12690c Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 28 Dec 2015 13:37:56 +0100 Subject: [PATCH] U4-7614 Allow Examine's local temp storage to exist in the current User's temp storage location - useful for Azure --- .../AzureLocalStorageDirectory.cs | 30 ++++++++++++++ .../CodeGenLocalStorageDirectory.cs | 25 ++++++++++++ .../LocalStorage/ILocalStorageDirectory.cs | 13 +++++++ .../LocalStorage/LocalTempStorageIndexer.cs | 39 ++++++++++++++----- src/UmbracoExamine/UmbracoExamine.csproj | 3 ++ 5 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 src/UmbracoExamine/LocalStorage/AzureLocalStorageDirectory.cs create mode 100644 src/UmbracoExamine/LocalStorage/CodeGenLocalStorageDirectory.cs create mode 100644 src/UmbracoExamine/LocalStorage/ILocalStorageDirectory.cs diff --git a/src/UmbracoExamine/LocalStorage/AzureLocalStorageDirectory.cs b/src/UmbracoExamine/LocalStorage/AzureLocalStorageDirectory.cs new file mode 100644 index 0000000000..6d60d26079 --- /dev/null +++ b/src/UmbracoExamine/LocalStorage/AzureLocalStorageDirectory.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Specialized; +using System.IO; +using System.Web; +using Umbraco.Core; + +namespace UmbracoExamine.LocalStorage +{ + /// + /// When running on Azure websites, we can use the local user's storage space + /// + public sealed class AzureLocalStorageDirectory : ILocalStorageDirectory + { + public DirectoryInfo GetLocalStorageDirectory(NameValueCollection config, string configuredPath) + { + var appDomainHash = HttpRuntime.AppDomainAppId.ToMd5(); + var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "LuceneDir", + //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back + // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not + // utilizing an old index + appDomainHash, + //ensure the temp path is consistent with the configured path location + configuredPath.TrimStart('~', '/').Replace("/", "\\")); + var azureDir = new DirectoryInfo(cachePath); + if (azureDir.Exists == false) + azureDir.Create(); + return azureDir; + } + } +} \ No newline at end of file diff --git a/src/UmbracoExamine/LocalStorage/CodeGenLocalStorageDirectory.cs b/src/UmbracoExamine/LocalStorage/CodeGenLocalStorageDirectory.cs new file mode 100644 index 0000000000..eb7bb9a8b3 --- /dev/null +++ b/src/UmbracoExamine/LocalStorage/CodeGenLocalStorageDirectory.cs @@ -0,0 +1,25 @@ +using System.Collections.Specialized; +using System.IO; +using System.Web; + +namespace UmbracoExamine.LocalStorage +{ + /// + /// Use the ASP.Net CodeGen folder to store the index files + /// + /// + /// This is the default implementation - but it comes with it's own limitations - the CodeGen folder is cleared whenever new + /// DLLs are changed in the /bin folder (among other circumstances) which means the index would be re-synced (or rebuilt) there. + /// + public sealed class CodeGenLocalStorageDirectory : ILocalStorageDirectory + { + public DirectoryInfo GetLocalStorageDirectory(NameValueCollection config, string configuredPath) + { + var codegenPath = HttpRuntime.CodegenDir; + var path = Path.Combine(codegenPath, + //ensure the temp path is consistent with the configured path location + configuredPath.TrimStart('~', '/').Replace("/", "\\")); + return new DirectoryInfo(path); + } + } +} \ No newline at end of file diff --git a/src/UmbracoExamine/LocalStorage/ILocalStorageDirectory.cs b/src/UmbracoExamine/LocalStorage/ILocalStorageDirectory.cs new file mode 100644 index 0000000000..25d9afb857 --- /dev/null +++ b/src/UmbracoExamine/LocalStorage/ILocalStorageDirectory.cs @@ -0,0 +1,13 @@ +using System.Collections.Specialized; +using System.IO; + +namespace UmbracoExamine.LocalStorage +{ + /// + /// Used to resolve the local storage folder + /// + public interface ILocalStorageDirectory + { + DirectoryInfo GetLocalStorageDirectory(NameValueCollection config, string configuredPath); + } +} \ No newline at end of file diff --git a/src/UmbracoExamine/LocalStorage/LocalTempStorageIndexer.cs b/src/UmbracoExamine/LocalStorage/LocalTempStorageIndexer.cs index dc48fdc917..fe42a2e4e2 100644 --- a/src/UmbracoExamine/LocalStorage/LocalTempStorageIndexer.cs +++ b/src/UmbracoExamine/LocalStorage/LocalTempStorageIndexer.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Web; +using System.Web.Compilation; using Examine.LuceneEngine; using Lucene.Net.Analysis; using Lucene.Net.Index; @@ -42,9 +43,29 @@ namespace UmbracoExamine.LocalStorage public void Initialize(NameValueCollection config, string configuredPath, FSDirectory baseLuceneDirectory, Analyzer analyzer, LocalStorageType localStorageType) { - var codegenPath = HttpRuntime.CodegenDir; + ILocalStorageDirectory localStorateDir = new CodeGenLocalStorageDirectory(); + if (config["tempStorageDirectory"] != null) + { + //try to get the type + var dirType = BuildManager.GetType(config["tempStorageDirectory"], false); + if (dirType != null) + { + try + { + localStorateDir = (ILocalStorageDirectory)Activator.CreateInstance(dirType); + } + catch (Exception ex) + { + LogHelper.Error( + string.Format("Could not create a temp storage location of type {0}, reverting to use the " + typeof (CodeGenLocalStorageDirectory).FullName, dirType), + ex); + } + } + } - TempPath = Path.Combine(codegenPath, configuredPath.TrimStart('~', '/').Replace("/", "\\")); + var tempPath = localStorateDir.GetLocalStorageDirectory(config, configuredPath); + if (tempPath == null) throw new InvalidOperationException("Could not resolve a temp location from the " + localStorateDir.GetType() + " specified"); + TempPath = tempPath.FullName; switch (localStorageType) { @@ -101,7 +122,7 @@ namespace UmbracoExamine.LocalStorage baseLuceneDirectory, //Disable mirrored index, we're kind of screwed here only use master index true); - } + } break; case LocalStorageType.LocalOnly: @@ -234,7 +255,7 @@ namespace UmbracoExamine.LocalStorage IndexWriter.Unlock(dir); } - if (IndexWriter.IsLocked(dir) == false) return Attempt.Succeed(true); + if (IndexWriter.IsLocked(dir) == false) return Attempt.Succeed(true); LogHelper.Info("Could not acquire directory lock for {0} writer, retrying ....", dir.ToString); return Attempt.Fail(); }, 5, TimeSpan.FromSeconds(1)); @@ -267,7 +288,7 @@ namespace UmbracoExamine.LocalStorage { //NOTE: To date I've not seen this error occur using (writerAttempt.Result.GetReader()) - { + { } } catch (Exception ex) @@ -275,14 +296,14 @@ namespace UmbracoExamine.LocalStorage writerAttempt.Result.Dispose(); LogHelper.Error( - string.Format("Could not open an index reader, {0} is empty or corrupt... attempting to clear index files in master folder", configuredPath), + string.Format("Could not open an index reader, {0} is empty or corrupt... attempting to clear index files in master folder", configuredPath), ex); if (ClearLuceneDirFiles(baseLuceneDirectory) == false) { //hrm, not much we can do in this situation, but this shouldn't happen - LogHelper.Error("Could not open an index reader, index is corrupt.", ex); - return InitializeDirectoryFlags.FailedCorrupt; + LogHelper.Error("Could not open an index reader, index is corrupt.", ex); + return InitializeDirectoryFlags.FailedCorrupt; } //the main index is now blank, we'll proceed as normal with a new empty index... @@ -338,7 +359,7 @@ namespace UmbracoExamine.LocalStorage } LogHelper.Debug("Could not delete non synced index file file, index sync will continue but old index files will remain - this shouldn't affect indexing/searching operations. {0}", () => ex.ToString()); - + } } } diff --git a/src/UmbracoExamine/UmbracoExamine.csproj b/src/UmbracoExamine/UmbracoExamine.csproj index 835ee43ff2..baac44f0bf 100644 --- a/src/UmbracoExamine/UmbracoExamine.csproj +++ b/src/UmbracoExamine/UmbracoExamine.csproj @@ -124,6 +124,9 @@ + + +