Merge pull request #2233 from umbraco/temp-U4-10503-2

U4-10503 Umbraco plugins cache files should be stored in the same local temp location as the umbraco xml cache file
This commit is contained in:
Warren Buckley
2017-10-09 14:04:16 +01:00
committed by GitHub
4 changed files with 127 additions and 124 deletions

View File

@@ -41,7 +41,8 @@ namespace Umbraco.Core
private readonly IServiceProvider _serviceProvider;
private readonly IRuntimeCacheProvider _runtimeCache;
private readonly ProfilingLogger _logger;
private readonly string _tempFolder;
private readonly Lazy<string> _pluginListFilePath = new Lazy<string>(GetPluginListFilePath);
private readonly Lazy<string> _pluginHashFilePath = new Lazy<string>(GetPluginHashFilePath);
private readonly object _typesLock = new object();
private readonly Dictionary<TypeListKey, TypeList> _types = new Dictionary<TypeListKey, TypeList>();
@@ -67,14 +68,7 @@ namespace Umbraco.Core
_serviceProvider = serviceProvider;
_runtimeCache = runtimeCache;
_logger = logger;
// the temp folder where the cache file lives
_tempFolder = IOHelper.MapPath("~/App_Data/TEMP/PluginCache");
if (Directory.Exists(_tempFolder) == false)
Directory.CreateDirectory(_tempFolder);
var pluginListFile = GetPluginListFilePath();
if (detectChanges)
{
//first check if the cached hash is string.Empty, if it is then we need
@@ -82,23 +76,23 @@ namespace Umbraco.Core
RequiresRescanning = (CachedAssembliesHash != CurrentAssembliesHash) || CachedAssembliesHash == string.Empty;
//if they have changed, we need to write the new file
if (RequiresRescanning)
{
// if the hash has changed, clear out the persisted list no matter what, this will force
// rescanning of all plugin types including lazy ones.
// http://issues.umbraco.org/issue/U4-4789
if(File.Exists(pluginListFile))
File.Delete(pluginListFile);
{
// if the hash has changed, clear out the persisted list no matter what, this will force
// rescanning of all plugin types including lazy ones.
// http://issues.umbraco.org/issue/U4-4789
if(File.Exists(_pluginListFilePath.Value))
File.Delete(_pluginListFilePath.Value);
WriteCachePluginsHash();
}
}
else
{
// if the hash has changed, clear out the persisted list no matter what, this will force
// rescanning of all plugin types including lazy ones.
{
// if the hash has changed, clear out the persisted list no matter what, this will force
// rescanning of all plugin types including lazy ones.
// http://issues.umbraco.org/issue/U4-4789
if (File.Exists(pluginListFile))
File.Delete(pluginListFile);
if (File.Exists(_pluginListFilePath.Value))
File.Delete(_pluginListFilePath.Value);
// always set to true if we're not detecting (generally only for testing)
RequiresRescanning = true;
@@ -191,11 +185,10 @@ namespace Umbraco.Core
{
if (_cachedAssembliesHash != null)
return _cachedAssembliesHash;
if (File.Exists(_pluginHashFilePath.Value) == false) return string.Empty;
var filePath = GetPluginHashFilePath();
if (File.Exists(filePath) == false) return string.Empty;
var hash = File.ReadAllText(filePath, Encoding.UTF8);
var hash = File.ReadAllText(_pluginHashFilePath.Value, Encoding.UTF8);
_cachedAssembliesHash = hash;
return _cachedAssembliesHash;
@@ -233,17 +226,8 @@ namespace Umbraco.Core
/// Writes the assembly hash file.
/// </summary>
private void WriteCachePluginsHash()
{
var filePath = GetPluginHashFilePath();
// be absolutely sure the folder exists
var folder = Path.GetDirectoryName(filePath);
if (folder == null)
throw new InvalidOperationException("The folder could not be determined for the file " + filePath);
if (Directory.Exists(folder) == false)
Directory.CreateDirectory(folder);
File.WriteAllText(filePath, CurrentAssembliesHash.ToString(), Encoding.UTF8);
{
File.WriteAllText(_pluginHashFilePath.Value, CurrentAssembliesHash, Encoding.UTF8);
}
/// <summary>
@@ -286,7 +270,7 @@ namespace Umbraco.Core
}
}
}
return generator.GenerateHash();
return generator.GenerateHash();
}
}
}
@@ -326,7 +310,7 @@ namespace Umbraco.Core
uniqInfos.Add(fileOrFolder.FullName);
generator.AddFileSystemItem(fileOrFolder);
}
return generator.GenerateHash();
return generator.GenerateHash();
}
}
}
@@ -359,12 +343,11 @@ namespace Umbraco.Core
{
return ReadCache();
}
catch
catch (Exception ex)
{
try
{
var filePath = GetPluginListFilePath();
File.Delete(filePath);
File.Delete(_pluginListFilePath.Value);
}
catch
{
@@ -378,12 +361,11 @@ namespace Umbraco.Core
internal Dictionary<Tuple<string, string>, IEnumerable<string>> ReadCache()
{
var cache = new Dictionary<Tuple<string, string>, IEnumerable<string>>();
var filePath = GetPluginListFilePath();
if (File.Exists(filePath) == false)
if (File.Exists(_pluginListFilePath.Value) == false)
return cache;
using (var stream = GetFileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, ListFileOpenReadTimeout))
using (var stream = GetFileStream(_pluginListFilePath.Value, FileMode.Open, FileAccess.Read, FileShare.Read, ListFileOpenReadTimeout))
using (var reader = new StreamReader(stream))
{
while (true)
@@ -426,23 +408,23 @@ namespace Umbraco.Core
/// <remarks>Generally only used for resetting cache, for example during the install process.</remarks>
public void ClearPluginCache()
{
var path = GetPluginListFilePath();
if (File.Exists(path))
File.Delete(path);
path = GetPluginHashFilePath();
if (File.Exists(path))
File.Delete(path);
if (File.Exists(_pluginListFilePath.Value))
File.Delete(_pluginListFilePath.Value);
if (File.Exists(_pluginHashFilePath.Value))
File.Delete(_pluginHashFilePath.Value);
_runtimeCache.ClearCacheItem(CacheKey);
}
private string GetPluginListFilePath()
{
private static string GetPluginListFilePath()
{
string pluginListFilePath;
switch (GlobalSettings.LocalTempStorageLocation)
{
case LocalTempStorage.AspNetTemp:
return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco-plugins.list");
pluginListFilePath = Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco-plugins.list");
break;
case LocalTempStorage.EnvironmentTemp:
var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1();
var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData",
@@ -450,19 +432,33 @@ namespace Umbraco.Core
// 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 path
appDomainHash);
return Path.Combine(cachePath, "umbraco-plugins.list");
pluginListFilePath = Path.Combine(cachePath, "umbraco-plugins.list");
break;
case LocalTempStorage.Default:
default:
return Path.Combine(_tempFolder, "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".list");
var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/PluginCache");
pluginListFilePath = Path.Combine(tempFolder, "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".list");
break;
}
//ensure the folder exists
var folder = Path.GetDirectoryName(pluginListFilePath);
if (folder == null)
throw new InvalidOperationException("The folder could not be determined for the file " + pluginListFilePath);
if (Directory.Exists(folder) == false)
Directory.CreateDirectory(folder);
return pluginListFilePath;
}
private string GetPluginHashFilePath()
private static string GetPluginHashFilePath()
{
string pluginHashFilePath;
switch (GlobalSettings.LocalTempStorageLocation)
{
case LocalTempStorage.AspNetTemp:
return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco-plugins.hash");
pluginHashFilePath = Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco-plugins.hash");
break;
case LocalTempStorage.EnvironmentTemp:
var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1();
var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData",
@@ -470,25 +466,28 @@ namespace Umbraco.Core
// 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 path
appDomainHash);
return Path.Combine(cachePath, "umbraco-plugins.hash");
pluginHashFilePath = Path.Combine(cachePath, "umbraco-plugins.hash");
break;
case LocalTempStorage.Default:
default:
return Path.Combine(_tempFolder, "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".hash");
var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/PluginCache");
pluginHashFilePath = Path.Combine(tempFolder, "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".hash");
break;
}
//ensure the folder exists
var folder = Path.GetDirectoryName(pluginHashFilePath);
if (folder == null)
throw new InvalidOperationException("The folder could not be determined for the file " + pluginHashFilePath);
if (Directory.Exists(folder) == false)
Directory.CreateDirectory(folder);
return pluginHashFilePath;
}
internal void WriteCache()
{
var filePath = GetPluginListFilePath();
// be absolutely sure the folder exists
var folder = Path.GetDirectoryName(filePath);
if (folder == null)
throw new InvalidOperationException("The folder could not be determined for the file " + filePath);
if (Directory.Exists(folder) == false)
Directory.CreateDirectory(folder);
using (var stream = GetFileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, ListFileOpenWriteTimeout))
using (var stream = GetFileStream(_pluginListFilePath.Value, FileMode.Create, FileAccess.Write, FileShare.None, ListFileOpenWriteTimeout))
using (var writer = new StreamWriter(stream))
{
foreach (var typeList in _types.Values)
@@ -504,8 +503,7 @@ namespace Umbraco.Core
internal void UpdateCache()
{
// note
// at the moment we write the cache to disk every time we update it. ideally we defer the writing
// TODO: at the moment we write the cache to disk every time we update it. ideally we defer the writing
// since all the updates are going to happen in a row when Umbraco starts. that being said, the
// file is small enough, so it is not a priority.
WriteCache();
@@ -518,13 +516,13 @@ namespace Umbraco.Core
while (true)
{
try
{
{
return new FileStream(path, fileMode, fileAccess, fileShare);
}
catch
catch (Exception ex)
{
if (--attempts == 0)
throw;
throw;
LogHelper.Debug<PluginManager>(string.Format("Attempted to get filestream for file {0} failed, {1} attempts left, pausing for {2} milliseconds", path, attempts, pauseMilliseconds));
Thread.Sleep(pauseMilliseconds);
@@ -734,7 +732,7 @@ namespace Umbraco.Core
// else proceed,
typeList = new TypeList(baseType, attributeType);
var scan = RequiresRescanning || File.Exists(GetPluginListFilePath()) == false;
var scan = RequiresRescanning || File.Exists(_pluginListFilePath.Value) == false;
if (scan)
{

View File

@@ -14,6 +14,7 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using umbraco.interfaces;
using Umbraco.Core.Configuration;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Sync
@@ -39,6 +40,7 @@ namespace Umbraco.Core.Sync
private bool _syncing;
private bool _released;
private readonly ProfilingLogger _profilingLogger;
private readonly Lazy<string> _distCacheFilePath = new Lazy<string>(GetDistCacheFilePath);
protected DatabaseServerMessengerOptions Options { get; private set; }
protected ApplicationContext ApplicationContext { get { return _appContext; } }
@@ -460,10 +462,9 @@ namespace Umbraco.Core.Sync
/// </remarks>
private void ReadLastSynced()
{
var path = SyncFilePath;
if (File.Exists(path) == false) return;
if (File.Exists(_distCacheFilePath.Value) == false) return;
var content = File.ReadAllText(path);
var content = File.ReadAllText(_distCacheFilePath.Value);
int last;
if (int.TryParse(content, out last))
_lastId = last;
@@ -478,7 +479,7 @@ namespace Umbraco.Core.Sync
/// </remarks>
private void SaveLastSynced(int id)
{
File.WriteAllText(SyncFilePath, id.ToString(CultureInfo.InvariantCulture));
File.WriteAllText(_distCacheFilePath.Value, id.ToString(CultureInfo.InvariantCulture));
_lastId = id;
}
@@ -498,20 +499,40 @@ namespace Umbraco.Core.Sync
+ "/D" + AppDomain.CurrentDomain.Id // eg 22
+ "] " + Guid.NewGuid().ToString("N").ToUpper(); // make it truly unique
/// <summary>
/// Gets the sync file path for the local server.
/// </summary>
/// <returns>The sync file path for the local server.</returns>
private static string SyncFilePath
private static string GetDistCacheFilePath()
{
get
{
var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/DistCache/" + NetworkHelper.FileSafeMachineName);
if (Directory.Exists(tempFolder) == false)
Directory.CreateDirectory(tempFolder);
var fileName = HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty) + "-lastsynced.txt";
return Path.Combine(tempFolder, HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty) + "-lastsynced.txt");
string distCacheFilePath;
switch (GlobalSettings.LocalTempStorageLocation)
{
case LocalTempStorage.AspNetTemp:
distCacheFilePath = Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData", fileName);
break;
case LocalTempStorage.EnvironmentTemp:
var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1();
var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData",
//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 path
appDomainHash);
distCacheFilePath = Path.Combine(cachePath, fileName);
break;
case LocalTempStorage.Default:
default:
var tempFolder = IOHelper.MapPath("~/App_Data/TEMP/DistCache");
distCacheFilePath = Path.Combine(tempFolder, fileName);
break;
}
//ensure the folder exists
var folder = Path.GetDirectoryName(distCacheFilePath);
if (folder == null)
throw new InvalidOperationException("The folder could not be determined for the file " + distCacheFilePath);
if (Directory.Exists(folder) == false)
Directory.CreateDirectory(folder);
return distCacheFilePath;
}
#endregion

View File

@@ -20,7 +20,7 @@ using Umbraco.Tests.TestHelpers.Entities;
namespace Umbraco.Tests.Models
{
[TestFixture]
public class ContentTests : BaseUmbracoConfigurationTest
public class ContentTests : BaseUmbracoApplicationTest
{
[SetUp]
public void Init()

View File

@@ -118,25 +118,12 @@ namespace Umbraco.Tests.TestHelpers
});
}
/// <summary>
/// By default this returns false which means the plugin manager will not be reset so it doesn't need to re-scan
/// all of the assemblies. Inheritors can override this if plugin manager resetting is required, generally needs
/// to be set to true if the SetupPluginManager has been overridden.
/// </summary>
protected virtual bool PluginManagerResetRequired
{
get { return false; }
}
/// <summary>
/// Inheritors can resset the plugin manager if they choose to on teardown
/// </summary>
protected virtual void ResetPluginManager()
{
if (PluginManagerResetRequired)
{
PluginManager.Current = null;
}
PluginManager.Current = null;
}
protected virtual CacheHelper CreateCacheHelper()
@@ -185,26 +172,23 @@ namespace Umbraco.Tests.TestHelpers
/// </summary>
protected virtual void SetupPluginManager()
{
if (PluginManager.Current == null || PluginManagerResetRequired)
PluginManager.Current = new PluginManager(
new ActivatorServiceProvider(),
CacheHelper.RuntimeCache, ProfilingLogger, false)
{
PluginManager.Current = new PluginManager(
new ActivatorServiceProvider(),
CacheHelper.RuntimeCache, ProfilingLogger, false)
AssembliesToScan = new[]
{
AssembliesToScan = new[]
{
Assembly.Load("Umbraco.Core"),
Assembly.Load("umbraco"),
Assembly.Load("Umbraco.Tests"),
Assembly.Load("businesslogic"),
Assembly.Load("cms"),
Assembly.Load("controls"),
Assembly.Load("umbraco.editorControls"),
Assembly.Load("umbraco.MacroEngines"),
Assembly.Load("umbraco.providers"),
}
};
}
Assembly.Load("Umbraco.Core"),
Assembly.Load("umbraco"),
Assembly.Load("Umbraco.Tests"),
Assembly.Load("businesslogic"),
Assembly.Load("cms"),
Assembly.Load("controls"),
Assembly.Load("umbraco.editorControls"),
Assembly.Load("umbraco.MacroEngines"),
Assembly.Load("umbraco.providers"),
}
};
}
/// <summary>