From f7097d571c653b14aa92bb63c2950cf8ef3e96d5 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Aug 2017 11:38:57 +1000 Subject: [PATCH 1/3] U4-10301 Change the PluginManager hash to use more reliable and consistent hashes --- src/Umbraco.Core/HashCodeCombiner.cs | 6 +- src/Umbraco.Core/HashGenerator.cs | 154 +++++++++++++++ src/Umbraco.Core/PluginManager.cs | 115 +++++------ src/Umbraco.Core/StringExtensions.cs | 2 +- .../Sync/WebServiceServerMessenger.cs | 10 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + src/Umbraco.Tests/HashCodeCombinerTests.cs | 2 +- src/Umbraco.Tests/HashGeneratorTests.cs | 184 ++++++++++++++++++ .../Plugins/PluginManagerTests.cs | 10 +- .../Strings/StringExtensionsTests.cs | 2 +- src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 11 files changed, 405 insertions(+), 82 deletions(-) create mode 100644 src/Umbraco.Core/HashGenerator.cs create mode 100644 src/Umbraco.Tests/HashGeneratorTests.cs diff --git a/src/Umbraco.Core/HashCodeCombiner.cs b/src/Umbraco.Core/HashCodeCombiner.cs index d3a55d5256..5f99c65787 100644 --- a/src/Umbraco.Core/HashCodeCombiner.cs +++ b/src/Umbraco.Core/HashCodeCombiner.cs @@ -2,17 +2,19 @@ using System.Globalization; using System.IO; using System.Linq; -using System.Text; namespace Umbraco.Core { /// - /// Used to create a hash code from multiple objects. + /// Used to create a .NET HashCode from multiple objects. /// /// /// .Net has a class the same as this: System.Web.Util.HashCodeCombiner and of course it works for all sorts of things /// which we've not included here as we just need a quick easy class for this in order to create a unique /// hash of directories/files to see if they have changed. + /// + /// NOTE: It's probably best to not relying on the hashing result across AppDomains! If you need a constant/reliable hash value + /// between AppDomains use SHA1. This is perfect for hashing things in a very fast way for a single AppDomain. /// internal class HashCodeCombiner { diff --git a/src/Umbraco.Core/HashGenerator.cs b/src/Umbraco.Core/HashGenerator.cs new file mode 100644 index 0000000000..7306dc9045 --- /dev/null +++ b/src/Umbraco.Core/HashGenerator.cs @@ -0,0 +1,154 @@ +using System; +using System.Globalization; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace Umbraco.Core +{ + /// + /// Used to generate a string hash using crypto libraries over multiple objects + /// + /// + /// This should be used to generate a reliable hash that survives AppDomain restarts. + /// This will use the crypto libs to generate the hash and will try to ensure that + /// strings, etc... are not re-allocated so it's not consuming much memory. + /// + internal class HashGenerator : DisposableObject + { + public HashGenerator() + { + _writer = new StreamWriter(_ms, Encoding.Unicode, 1024, leaveOpen: true); + } + + private readonly MemoryStream _ms = new MemoryStream(); + private StreamWriter _writer; + + internal void AddInt(int i) + { + _writer.Write(i); + } + + internal void AddLong(long i) + { + _writer.Write(i); + } + + internal void AddObject(object o) + { + _writer.Write(o); + } + + internal void AddDateTime(DateTime d) + { + _writer.Write(d.Ticks);; + } + + internal void AddString(string s) + { + if (s != null) + _writer.Write(s); + } + + internal void AddCaseInsensitiveString(string s) + { + //I've tried to no allocate a new string with this which can be done if we use the CompareInfo.GetSortKey method which will create a new + //byte array that we can use to write to the output, however this also allocates new objects so i really don't think the performance + //would be much different. In any case, i'll leave this here for reference. We could write the bytes out based on the sort key, + //this is how we could deal with case insensitivity without allocating another string + //for reference see: https://stackoverflow.com/a/10452967/694494 + //we could go a step further and s.Normalize() but we're not really dealing with crazy unicode with this class so far. + + if (s != null) + _writer.Write(s.ToUpperInvariant()); + } + + internal void AddFileSystemItem(FileSystemInfo f) + { + //if it doesn't exist, don't proceed. + if (f.Exists == false) + return; + + AddCaseInsensitiveString(f.FullName); + AddDateTime(f.CreationTimeUtc); + AddDateTime(f.LastWriteTimeUtc); + + //check if it is a file or folder + var fileInfo = f as FileInfo; + if (fileInfo != null) + { + AddLong(fileInfo.Length); + } + + var dirInfo = f as DirectoryInfo; + if (dirInfo != null) + { + foreach (var d in dirInfo.GetFiles()) + { + AddFile(d); + } + foreach (var s in dirInfo.GetDirectories()) + { + AddFolder(s); + } + } + } + + internal void AddFile(FileInfo f) + { + AddFileSystemItem(f); + } + + internal void AddFolder(DirectoryInfo d) + { + AddFileSystemItem(d); + } + + /// + /// Returns the generated hash output of all added objects + /// + /// + internal string GenerateHash() + { + //flush,close,dispose the writer,then create a new one since it's possible to keep adding after GenerateHash is called. + + _writer.Flush(); + _writer.Close(); + _writer.Dispose(); + _writer = new StreamWriter(_ms, Encoding.UTF8, 1024, leaveOpen: true); + + var hashType = CryptoConfig.AllowOnlyFipsAlgorithms ? "SHA1" : "MD5"; + + //create an instance of the correct hashing provider based on the type passed in + var hasher = HashAlgorithm.Create(hashType); + if (hasher == null) throw new InvalidOperationException("No hashing type found by name " + hashType); + using (hasher) + { + var buffer = _ms.GetBuffer(); + //get the hashed values created by our selected provider + var hashedByteArray = hasher.ComputeHash(buffer); + + //create a StringBuilder object + var stringBuilder = new StringBuilder(); + + //loop to each each byte + foreach (var b in hashedByteArray) + { + //append it to our StringBuilder + stringBuilder.Append(b.ToString("x2")); + } + + //return the hashed value + return stringBuilder.ToString(); + } + } + + protected override void DisposeResources() + { + _writer.Close(); + _writer.Dispose(); + _ms.Close(); + _ms.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/PluginManager.cs b/src/Umbraco.Core/PluginManager.cs index fe9236c58c..30029d2c87 100644 --- a/src/Umbraco.Core/PluginManager.cs +++ b/src/Umbraco.Core/PluginManager.cs @@ -44,8 +44,8 @@ namespace Umbraco.Core private readonly object _typesLock = new object(); private readonly Dictionary _types = new Dictionary(); - private long _cachedAssembliesHash = -1; - private long _currentAssembliesHash = -1; + private string _cachedAssembliesHash = null; + private string _currentAssembliesHash = null; private IEnumerable _assemblies; private bool _reportedChange; @@ -75,9 +75,9 @@ namespace Umbraco.Core if (detectChanges) { - //first check if the cached hash is 0, if it is then we ne + //first check if the cached hash is string.Empty, if it is then we need //do the check if they've changed - RequiresRescanning = (CachedAssembliesHash != CurrentAssembliesHash) || CachedAssembliesHash == 0; + RequiresRescanning = (CachedAssembliesHash != CurrentAssembliesHash) || CachedAssembliesHash == string.Empty; //if they have changed, we need to write the new file if (RequiresRescanning) { @@ -180,23 +180,20 @@ namespace Umbraco.Core /// /// Gets the currently cached hash value of the scanned assemblies. /// - /// The cached hash value, or 0 if no cache is found. - internal long CachedAssembliesHash + /// The cached hash value, or string.Empty if no cache is found. + internal string CachedAssembliesHash { get { - if (_cachedAssembliesHash != -1) + if (_cachedAssembliesHash != null) return _cachedAssembliesHash; var filePath = GetPluginHashFilePath(); - if (File.Exists(filePath) == false) return 0; + if (File.Exists(filePath) == false) return string.Empty; var hash = File.ReadAllText(filePath, Encoding.UTF8); - - long val; - if (long.TryParse(hash, out val) == false) return 0; - - _cachedAssembliesHash = val; + + _cachedAssembliesHash = hash; return _cachedAssembliesHash; } } @@ -205,11 +202,11 @@ namespace Umbraco.Core /// Gets the current assemblies hash based on creating a hash from the assemblies in various places. /// /// The current hash. - internal long CurrentAssembliesHash + internal string CurrentAssembliesHash { get { - if (_currentAssembliesHash != -1) + if (_currentAssembliesHash != null) return _currentAssembliesHash; _currentAssembliesHash = GetFileHash(new List> @@ -245,41 +242,40 @@ namespace Umbraco.Core /// The hash. /// Each file is a tuple containing the FileInfo object and a boolean which indicates whether to hash the /// file properties (false) or the file contents (true). - internal static long GetFileHash(IEnumerable> filesAndFolders, ProfilingLogger logger) + internal static string GetFileHash(IEnumerable> filesAndFolders, ProfilingLogger logger) { using (logger.TraceDuration("Determining hash of code files on disk", "Hash determined")) - { - var hashCombiner = new HashCodeCombiner(); - + { // get the distinct file infos to hash var uniqInfos = new HashSet(); var uniqContent = new HashSet(); - - foreach (var fileOrFolder in filesAndFolders) + using (var generator = new HashGenerator()) { - var info = fileOrFolder.Item1; - if (fileOrFolder.Item2) + foreach (var fileOrFolder in filesAndFolders) { - // add each unique file's contents to the hash - // normalize the content for cr/lf and case-sensitivity - - if (uniqContent.Contains(info.FullName)) continue; - uniqContent.Add(info.FullName); - if (File.Exists(info.FullName) == false) continue; - var content = RemoveCrLf(File.ReadAllText(info.FullName)); - hashCombiner.AddCaseInsensitiveString(content); + var info = fileOrFolder.Item1; + if (fileOrFolder.Item2) + { + // add each unique file's contents to the hash + // normalize the content for cr/lf and case-sensitivity + if (uniqContent.Add(info.FullName)) + { + if (File.Exists(info.FullName) == false) continue; + var content = RemoveCrLf(File.ReadAllText(info.FullName)); + generator.AddCaseInsensitiveString(content); + } + } + else + { + // add each unique folder/file to the hash + if (uniqInfos.Add(info.FullName)) + { + generator.AddFileSystemItem(info); + } + } } - else - { - // add each unique folder/file to the hash - - if (uniqInfos.Contains(info.FullName)) continue; - uniqInfos.Add(info.FullName); - hashCombiner.AddFileSystemItem(info); - } - } - - return ConvertHashToInt64(hashCombiner.GetCombinedHashCode()); + return generator.GenerateHash(); + } } } @@ -303,34 +299,25 @@ namespace Umbraco.Core /// A collection of files. /// A profiling logger. /// The hash. - internal static long GetFileHash(IEnumerable filesAndFolders, ProfilingLogger logger) + internal static string GetFileHash(IEnumerable filesAndFolders, ProfilingLogger logger) { using (logger.TraceDuration("Determining hash of code files on disk", "Hash determined")) { - var hashCombiner = new HashCodeCombiner(); - - // get the distinct file infos to hash - var uniqInfos = new HashSet(); - - foreach (var fileOrFolder in filesAndFolders) + using (var generator = new HashGenerator()) { - if (uniqInfos.Contains(fileOrFolder.FullName)) continue; - uniqInfos.Add(fileOrFolder.FullName); - hashCombiner.AddFileSystemItem(fileOrFolder); - } + // get the distinct file infos to hash + var uniqInfos = new HashSet(); - return ConvertHashToInt64(hashCombiner.GetCombinedHashCode()); + foreach (var fileOrFolder in filesAndFolders) + { + if (uniqInfos.Contains(fileOrFolder.FullName)) continue; + uniqInfos.Add(fileOrFolder.FullName); + generator.AddFileSystemItem(fileOrFolder); + } + return generator.GenerateHash(); + } } - } - - /// - /// Converts a string hash value into an Int64. - /// - internal static long ConvertHashToInt64(string val) - { - long outVal; - return long.TryParse(val, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out outVal) ? outVal : 0; - } + } #endregion diff --git a/src/Umbraco.Core/StringExtensions.cs b/src/Umbraco.Core/StringExtensions.cs index dba7f2cfee..b9b9e478dc 100644 --- a/src/Umbraco.Core/StringExtensions.cs +++ b/src/Umbraco.Core/StringExtensions.cs @@ -759,7 +759,7 @@ namespace Umbraco.Core foreach (var b in hashedByteArray) { //append it to our StringBuilder - stringBuilder.Append(b.ToString("x2").ToLower()); + stringBuilder.Append(b.ToString("x2")); } //return the hashed value diff --git a/src/Umbraco.Core/Sync/WebServiceServerMessenger.cs b/src/Umbraco.Core/Sync/WebServiceServerMessenger.cs index e5717fbfdc..09b845d29a 100644 --- a/src/Umbraco.Core/Sync/WebServiceServerMessenger.cs +++ b/src/Umbraco.Core/Sync/WebServiceServerMessenger.cs @@ -126,10 +126,12 @@ namespace Umbraco.Core.Sync public static string GetServerHash(string machineName, string appDomainAppId) { - var hasher = new HashCodeCombiner(); - hasher.AddCaseInsensitiveString(appDomainAppId); - hasher.AddCaseInsensitiveString(machineName); - return hasher.GetCombinedHashCode(); + using (var generator = new HashGenerator()) + { + generator.AddString(machineName); + generator.AddString(appDomainAppId); + return generator.GenerateHash(); + } } protected override bool RequiresDistributed(IEnumerable servers, ICacheRefresher refresher, MessageType messageType) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 24fdf32150..5fa4325814 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -342,6 +342,7 @@ + diff --git a/src/Umbraco.Tests/HashCodeCombinerTests.cs b/src/Umbraco.Tests/HashCodeCombinerTests.cs index 8d1ad021dd..08eacd655b 100644 --- a/src/Umbraco.Tests/HashCodeCombinerTests.cs +++ b/src/Umbraco.Tests/HashCodeCombinerTests.cs @@ -6,7 +6,7 @@ using Umbraco.Core; namespace Umbraco.Tests { - [TestFixture] + [TestFixture] public class HashCodeCombinerTests { diff --git a/src/Umbraco.Tests/HashGeneratorTests.cs b/src/Umbraco.Tests/HashGeneratorTests.cs new file mode 100644 index 0000000000..179b4eaeaa --- /dev/null +++ b/src/Umbraco.Tests/HashGeneratorTests.cs @@ -0,0 +1,184 @@ +using System; +using System.IO; +using System.Reflection; +using NUnit.Framework; +using Umbraco.Core; + +namespace Umbraco.Tests +{ + [TestFixture] + public class HashGeneratorTests + { + private string Generate(bool isCaseSensitive, params string[] strs) + { + using (var generator = new HashGenerator()) + { + foreach (var str in strs) + { + if (isCaseSensitive) + generator.AddString(str); + else + generator.AddCaseInsensitiveString(str); + } + return generator.GenerateHash(); + } + } + + [Test] + public void Generate_Hash_Multiple_Strings_Case_Sensitive() + { + + var hash1 = Generate(true, "hello", "world"); + var hash2 = Generate(true, "hello", "world"); + var hashFalse1 = Generate(true, "hello", "worlD"); + var hashFalse2 = Generate(true, "hEllo", "world"); + + Assert.AreEqual(hash1, hash2); + Assert.AreNotEqual(hash1, hashFalse1); + Assert.AreNotEqual(hash1, hashFalse2); + } + + [Test] + public void Generate_Hash_Multiple_Strings_Case_Insensitive() + { + var hash1 = Generate(false, "hello", "world"); + var hash2 = Generate(false, "hello", "world"); + var hashFalse1 = Generate(false, "hello", "worlD"); + var hashFalse2 = Generate(false, "hEllo", "world"); + + Assert.AreEqual(hash1, hash2); + Assert.AreEqual(hash1, hashFalse1); + Assert.AreEqual(hash1, hashFalse2); + } + + private DirectoryInfo PrepareFolder() + { + var assDir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; + var dir = Directory.CreateDirectory(Path.Combine(assDir.FullName, "HashCombiner", Guid.NewGuid().ToString("N"))); + foreach (var f in dir.GetFiles()) + { + f.Delete(); + } + return dir; + } + + [Test] + public void HashCombiner_Test_String() + { + using (var combiner1 = new HashGenerator()) + using (var combiner2 = new HashGenerator()) + { + combiner1.AddCaseInsensitiveString("Hello"); + combiner2.AddCaseInsensitiveString("hello"); + Assert.AreEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); + combiner2.AddCaseInsensitiveString("world"); + Assert.AreNotEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); + } + + } + + [Test] + public void HashCombiner_Test_Int() + { + using (var combiner1 = new HashGenerator()) + using (var combiner2 = new HashGenerator()) + { + combiner1.AddInt(1234); + combiner2.AddInt(1234); + Assert.AreEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); + combiner2.AddInt(1); + Assert.AreNotEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); + } + } + + [Test] + public void HashCombiner_Test_DateTime() + { + using (var combiner1 = new HashGenerator()) + using (var combiner2 = new HashGenerator()) + { + var dt = DateTime.Now; + combiner1.AddDateTime(dt); + combiner2.AddDateTime(dt); + Assert.AreEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); + combiner2.AddDateTime(DateTime.Now); + Assert.AreNotEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); + } + } + + [Test] + public void HashCombiner_Test_File() + { + using (var combiner1 = new HashGenerator()) + using (var combiner2 = new HashGenerator()) + using (var combiner3 = new HashGenerator()) + { + var dir = PrepareFolder(); + var file1Path = Path.Combine(dir.FullName, "hastest1.txt"); + File.Delete(file1Path); + using (var file1 = File.CreateText(Path.Combine(dir.FullName, "hastest1.txt"))) + { + file1.WriteLine("hello"); + } + var file2Path = Path.Combine(dir.FullName, "hastest2.txt"); + File.Delete(file2Path); + using (var file2 = File.CreateText(Path.Combine(dir.FullName, "hastest2.txt"))) + { + //even though files are the same, the dates are different + file2.WriteLine("hello"); + } + + combiner1.AddFile(new FileInfo(file1Path)); + + combiner2.AddFile(new FileInfo(file1Path)); + + combiner3.AddFile(new FileInfo(file2Path)); + + Assert.AreEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); + Assert.AreNotEqual(combiner1.GenerateHash(), combiner3.GenerateHash()); + + combiner2.AddFile(new FileInfo(file2Path)); + + Assert.AreNotEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); + } + } + + [Test] + public void HashCombiner_Test_Folder() + { + using (var combiner1 = new HashGenerator()) + using (var combiner2 = new HashGenerator()) + using (var combiner3 = new HashGenerator()) + { + var dir = PrepareFolder(); + var file1Path = Path.Combine(dir.FullName, "hastest1.txt"); + File.Delete(file1Path); + using (var file1 = File.CreateText(Path.Combine(dir.FullName, "hastest1.txt"))) + { + file1.WriteLine("hello"); + } + + //first test the whole folder + combiner1.AddFolder(dir); + + combiner2.AddFolder(dir); + + Assert.AreEqual(combiner1.GenerateHash(), combiner2.GenerateHash()); + + //now add a file to the folder + + var file2Path = Path.Combine(dir.FullName, "hastest2.txt"); + File.Delete(file2Path); + using (var file2 = File.CreateText(Path.Combine(dir.FullName, "hastest2.txt"))) + { + //even though files are the same, the dates are different + file2.WriteLine("hello"); + } + + combiner3.AddFolder(dir); + + Assert.AreNotEqual(combiner1.GenerateHash(), combiner3.GenerateHash()); + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Plugins/PluginManagerTests.cs b/src/Umbraco.Tests/Plugins/PluginManagerTests.cs index 333970bf67..15d7a7ffda 100644 --- a/src/Umbraco.Tests/Plugins/PluginManagerTests.cs +++ b/src/Umbraco.Tests/Plugins/PluginManagerTests.cs @@ -218,15 +218,7 @@ AnotherContentFinder //ensure they are all found Assert.IsTrue(plugins.Result.ContainsAll(shouldContain)); } - - [Test] - public void PluginHash_From_String() - { - var s = "hello my name is someone".GetHashCode().ToString("x", CultureInfo.InvariantCulture); - var output = PluginManager.ConvertHashToInt64(s); - Assert.AreNotEqual(0, output); - } - + [Test] public void Get_Plugins_Hash() { diff --git a/src/Umbraco.Tests/Strings/StringExtensionsTests.cs b/src/Umbraco.Tests/Strings/StringExtensionsTests.cs index 199bd9254d..e0e80f3ab2 100644 --- a/src/Umbraco.Tests/Strings/StringExtensionsTests.cs +++ b/src/Umbraco.Tests/Strings/StringExtensionsTests.cs @@ -24,7 +24,7 @@ namespace Umbraco.Tests.Strings { ShortStringHelperResolver.Reset(); } - + [TestCase("hello", "world", false)] [TestCase("hello", "hello", true)] [TestCase("hellohellohellohellohellohellohello", "hellohellohellohellohellohellohelloo", false)] diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 067109d8bf..5048bad14e 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -165,6 +165,7 @@ + From 300c9aa25815b2c713a33f93e04a4eea77c8abbe Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 17 Aug 2017 12:10:34 +1000 Subject: [PATCH 2/3] fix test --- src/Umbraco.Tests/Cache/CacheRefresherTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Tests/Cache/CacheRefresherTests.cs b/src/Umbraco.Tests/Cache/CacheRefresherTests.cs index 33dfd16743..189848651a 100644 --- a/src/Umbraco.Tests/Cache/CacheRefresherTests.cs +++ b/src/Umbraco.Tests/Cache/CacheRefresherTests.cs @@ -9,10 +9,10 @@ namespace Umbraco.Tests.Cache public class CacheRefresherTests { [TestCase("", "123456", "testmachine", true)] //empty hash will continue - [TestCase("fffffff28449cf33", "123456", "testmachine", false)] //match, don't continue - [TestCase("fffffff28449cf33", "12345", "testmachine", true)] // no match, continue - [TestCase("fffffff28449cf33", "123456", "testmachin", true)] // same - [TestCase("fffffff28449cf3", "123456", "testmachine", true)] // same + [TestCase("2e6deefea4444a69dbd15a01b4c2749d", "123456", "testmachine", false)] //match, don't continue + [TestCase("2e6deefea4444a69dbd15a01b4c2749d", "12345", "testmachine", true)] // no match, continue + [TestCase("2e6deefea4444a69dbd15a01b4c2749d", "123456", "testmachin", true)] // same + [TestCase("2e6deefea4444a69dbd15a01b4c2749", "123456", "testmachine", true)] // same public void Continue_Refreshing_For_Request(string hash, string appDomainAppId, string machineName, bool expected) { if (expected) From f2db0fe80e8cb98a5a87e0610cbcde1dbf5a9d8f Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Fri, 25 Aug 2017 22:00:41 +0200 Subject: [PATCH 3/3] U4-10358 Upgrade error from 7.1.8 to 7.6.5: The index 'IX_umbracoNodeUniqueID' is dependent on column 'uniqueID' Removes migration that would add wrongly named index to a table, only to immediately be removed again in 7.3.0 --- .../AddIndexToUmbracoNodeTable.cs | 46 ------------------- src/Umbraco.Core/Umbraco.Core.csproj | 1 - 2 files changed, 47 deletions(-) delete mode 100644 src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenTwoZero/AddIndexToUmbracoNodeTable.cs diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenTwoZero/AddIndexToUmbracoNodeTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenTwoZero/AddIndexToUmbracoNodeTable.cs deleted file mode 100644 index 7d5109a1db..0000000000 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenTwoZero/AddIndexToUmbracoNodeTable.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Linq; -using Umbraco.Core.Configuration; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence.DatabaseModelDefinitions; -using Umbraco.Core.Persistence.SqlSyntax; - -namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenTwoZero -{ - [Migration("7.2.0", 3, Constants.System.UmbracoMigrationName)] - public class AddIndexToUmbracoNodeTable : MigrationBase - { - private readonly bool _skipIndexCheck; - - internal AddIndexToUmbracoNodeTable(ISqlSyntaxProvider sqlSyntax, ILogger logger, bool skipIndexCheck) : base(sqlSyntax, logger) - { - _skipIndexCheck = skipIndexCheck; - } - - public AddIndexToUmbracoNodeTable(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger) - { - } - - public override void Up() - { - var dbIndexes = _skipIndexCheck ? new DbIndexDefinition[] { } : SqlSyntax.GetDefinedIndexes(Context.Database) - .Select(x => new DbIndexDefinition - { - TableName = x.Item1, - IndexName = x.Item2, - ColumnName = x.Item3, - IsUnique = x.Item4 - }).ToArray(); - - //make sure it doesn't already exist - if (dbIndexes.Any(x => x.IndexName.InvariantEquals("IX_umbracoNodeUniqueID")) == false) - { - Create.Index("IX_umbracoNodeUniqueID").OnTable("umbracoNode").OnColumn("uniqueID").Ascending().WithOptions().NonClustered(); - } - } - - public override void Down() - { - Delete.Index("IX_umbracoNodeUniqueID").OnTable("umbracoNode"); - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 228905226f..fcc2e5bb70 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -765,7 +765,6 @@ -