From 0cce4b435743f277d89c29b5ffb997785659ec97 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Tue, 26 Nov 2013 10:36:06 -0800 Subject: [PATCH] Lock ShellDescriptor cache The cache.dat files contains the enabled features for every tenants. This file is accessed in read/write by all tenants when they are loaded or changed. This can happen concurrently if tenants are activated in parallel, if multiple servers are using the same file system, or if multiple tenants get their features changed at the same time. This commit doesn't fix the case of multiple web roles accessing the same file system (WAWS). --- .../Descriptor/ShellDescriptorCache.cs | 70 ++++++++++--------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/src/Orchard/Environment/Descriptor/ShellDescriptorCache.cs b/src/Orchard/Environment/Descriptor/ShellDescriptorCache.cs index 93597f038..4193281b3 100644 --- a/src/Orchard/Environment/Descriptor/ShellDescriptorCache.cs +++ b/src/Orchard/Environment/Descriptor/ShellDescriptorCache.cs @@ -32,7 +32,7 @@ namespace Orchard.Environment.Descriptor { public class ShellDescriptorCache : IShellDescriptorCache { private readonly IAppDataFolder _appDataFolder; private const string DescriptorCacheFileName = "cache.dat"; - + private static readonly object _synLock = new object(); public ShellDescriptorCache(IAppDataFolder appDataFolder) { _appDataFolder = appDataFolder; T = NullLocalizer.Instance; @@ -47,48 +47,54 @@ namespace Orchard.Environment.Descriptor { [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "StringReader closed by XmlReader.")] public ShellDescriptor Fetch(string name) { - VerifyCacheFile(); - var text = _appDataFolder.ReadFile(DescriptorCacheFileName); - var xmlDocument = new XmlDocument(); - xmlDocument.LoadXml(text); - XmlNode rootNode = xmlDocument.DocumentElement; - if (rootNode != null) { - foreach (XmlNode tenantNode in rootNode.ChildNodes) { - if (String.Equals(tenantNode.Name, name, StringComparison.OrdinalIgnoreCase)) { - return GetShellDecriptorForCacheText(tenantNode.InnerText); + lock (_synLock) { + VerifyCacheFile(); + var text = _appDataFolder.ReadFile(DescriptorCacheFileName); + var xmlDocument = new XmlDocument(); + xmlDocument.LoadXml(text); + XmlNode rootNode = xmlDocument.DocumentElement; + if (rootNode != null) { + foreach (XmlNode tenantNode in rootNode.ChildNodes) { + if (String.Equals(tenantNode.Name, name, StringComparison.OrdinalIgnoreCase)) { + return GetShellDecriptorForCacheText(tenantNode.InnerText); + } } } + + return null; + } - return null; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "writer closed by xmlWriter.")] public void Store(string name, ShellDescriptor descriptor) { - VerifyCacheFile(); - var text = _appDataFolder.ReadFile(DescriptorCacheFileName); - bool tenantCacheUpdated = false; - var saveWriter = new StringWriter(); - var xmlDocument = new XmlDocument(); - xmlDocument.LoadXml(text); - XmlNode rootNode = xmlDocument.DocumentElement; - if (rootNode != null) { - foreach (XmlNode tenantNode in rootNode.ChildNodes) { - if (String.Equals(tenantNode.Name, name, StringComparison.OrdinalIgnoreCase)) { - tenantNode.InnerText = GetCacheTextForShellDescriptor(descriptor); - tenantCacheUpdated = true; - break; + lock (_synLock) { + VerifyCacheFile(); + var text = _appDataFolder.ReadFile(DescriptorCacheFileName); + bool tenantCacheUpdated = false; + var saveWriter = new StringWriter(); + var xmlDocument = new XmlDocument(); + xmlDocument.LoadXml(text); + XmlNode rootNode = xmlDocument.DocumentElement; + if (rootNode != null) { + foreach (XmlNode tenantNode in rootNode.ChildNodes) { + if (String.Equals(tenantNode.Name, name, StringComparison.OrdinalIgnoreCase)) { + tenantNode.InnerText = GetCacheTextForShellDescriptor(descriptor); + tenantCacheUpdated = true; + break; + } + } + if (!tenantCacheUpdated) { + XmlElement newTenant = xmlDocument.CreateElement(name); + newTenant.InnerText = GetCacheTextForShellDescriptor(descriptor); + rootNode.AppendChild(newTenant); } } - if (!tenantCacheUpdated) { - XmlElement newTenant = xmlDocument.CreateElement(name); - newTenant.InnerText = GetCacheTextForShellDescriptor(descriptor); - rootNode.AppendChild(newTenant); - } - } - xmlDocument.Save(saveWriter); - _appDataFolder.CreateFile(DescriptorCacheFileName, saveWriter.ToString()); + xmlDocument.Save(saveWriter); + _appDataFolder.CreateFile(DescriptorCacheFileName, saveWriter.ToString()); + } } #endregion