diff --git a/src/Geta.NotFoundHandler/Core/Redirects/CustomRedirectCollection.cs b/src/Geta.NotFoundHandler/Core/Redirects/CustomRedirectCollection.cs index fa782aa..eca9df4 100644 --- a/src/Geta.NotFoundHandler/Core/Redirects/CustomRedirectCollection.cs +++ b/src/Geta.NotFoundHandler/Core/Redirects/CustomRedirectCollection.cs @@ -19,14 +19,9 @@ public class CustomRedirectCollection : IEnumerable private readonly IEnumerable _providers = new List(); /// - /// Hashtable for quick lookup of old urls + /// URLs sorted Z-A. /// - private readonly Dictionary _quickLookupTable = new(StringComparer.OrdinalIgnoreCase); - - /// - /// Cache of URLs sorted ZA for look up of partially matched URLs - /// - private KeyValuePair[] _redirectsZACache; + private readonly SortedDictionary _redirectsZA = new(new ReverseStringComparer()); public CustomRedirectCollection() { @@ -39,7 +34,7 @@ public CustomRedirectCollection(IEnumerable providers) public IEnumerator GetEnumerator() { - return _quickLookupTable.Values.GetEnumerator(); + return _redirectsZA.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() @@ -79,34 +74,19 @@ public CustomRedirect Find(Uri urlNotFound) public void Add(CustomRedirect customRedirect) { var oldUrl = HttpUtility.UrlDecode(customRedirect.OldUrl); - if (_quickLookupTable.ContainsKey(oldUrl)) - { - _quickLookupTable[oldUrl] = customRedirect; - return; - } - - // Add to quick look up table too - _quickLookupTable.Add(oldUrl, customRedirect); - - // clean cache - _redirectsZACache = null; + _redirectsZA[oldUrl] = customRedirect; } private CustomRedirect FindInternal(string url) { url = HttpUtility.UrlDecode(url) ?? string.Empty; - if (_quickLookupTable.TryGetValue(url, out var redirect)) + if (_redirectsZA.TryGetValue(url, out var redirect)) { return redirect; } // working with local copy to avoid multi-threading issues - var redirectsZA = _redirectsZACache; - if (redirectsZA == null) - { - redirectsZA = _quickLookupTable.OrderByDescending(x => x.Key, StringComparer.OrdinalIgnoreCase).ToArray(); - _redirectsZACache = redirectsZA; - } + var redirectsZA = _redirectsZA.ToArray(); var path = url.AsPathSpan(); var query = url.AsQuerySpan(); diff --git a/src/Geta.NotFoundHandler/Core/Redirects/ReverseStringComparer.cs b/src/Geta.NotFoundHandler/Core/Redirects/ReverseStringComparer.cs new file mode 100644 index 0000000..8175f3b --- /dev/null +++ b/src/Geta.NotFoundHandler/Core/Redirects/ReverseStringComparer.cs @@ -0,0 +1,27 @@ +// Copyright (c) Geta Digital. All rights reserved. +// Licensed under Apache-2.0. See the LICENSE file in the project root for more information + +using System; +using System.Collections.Generic; + +namespace Geta.NotFoundHandler.Core.Redirects; + +/// +/// A comparer that sorts strings in reverse order. +/// +public class ReverseStringComparer : IComparer +{ + private readonly IComparer _baseComparer; + + public ReverseStringComparer() : this(StringComparer.OrdinalIgnoreCase) { } + + public ReverseStringComparer(IComparer baseComparer) + { + _baseComparer = baseComparer ?? throw new ArgumentNullException(nameof(baseComparer)); + } + + public int Compare(string x, string y) + { + return _baseComparer.Compare(y, x); + } +}