Reduce CPU time when initiating RepositoryCacheKeys (#18267)

* Avoid an unneeded lookups in the Keys dictionary when initiating key cache

* Add further comments and unit tests around updated code.

---------

Co-authored-by: Andy Butland <abutland73@gmail.com>
This commit is contained in:
Henrik
2025-03-26 16:01:53 +01:00
committed by GitHub
parent 37035e6e7f
commit 028da4545e
2 changed files with 49 additions and 2 deletions

View File

@@ -1,3 +1,5 @@
using System.Runtime.InteropServices;
namespace Umbraco.Cms.Core.Persistence.Repositories;
/// <summary>
@@ -5,15 +7,34 @@ namespace Umbraco.Cms.Core.Persistence.Repositories;
/// </summary>
public static class RepositoryCacheKeys
{
// used to cache keys so we don't keep allocating strings
/// <summary>
/// A cache for the keys we don't keep allocating strings.
/// </summary>
private static readonly Dictionary<Type, string> Keys = new();
/// <summary>
/// Gets the repository cache key for the provided type.
/// </summary>
public static string GetKey<T>()
{
Type type = typeof(T);
return Keys.TryGetValue(type, out var key) ? key : Keys[type] = "uRepo_" + type.Name + "_";
// The following code is a micro-optimization to avoid an unnecessary lookup in the Keys dictionary, when writing the newly created key.
// Previously, the code was:
// return Keys.TryGetValue(type, out var key)
// ? key
// : Keys[type] = "uRepo_" + type.Name + "_";
// Look up the existing value or get a reference to the newly created default value.
ref string? key = ref CollectionsMarshal.GetValueRefOrAddDefault(Keys, type, out _);
// As we have the reference, we can just assign it if null, without the expensive write back to the dictionary.
return key ??= "uRepo_" + type.Name + "_";
}
/// <summary>
/// Gets the repository cache key for the provided type and Id.
/// </summary>
public static string GetKey<T, TId>(TId? id)
{
if (EqualityComparer<TId?>.Default.Equals(id, default))

View File

@@ -0,0 +1,26 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using NUnit.Framework;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence.Repositories;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.PropertyEditors;
[TestFixture]
public class RepositoryCacheKeysTests
{
[Test]
public void GetKey_Returns_Expected_Key_For_Type()
{
var key = RepositoryCacheKeys.GetKey<IContent>();
Assert.AreEqual("uRepo_IContent_", key);
}
[Test]
public void GetKey_Returns_Expected_Key_For_Type_And_Id()
{
var key = RepositoryCacheKeys.GetKey<IContent, int>(1000);
Assert.AreEqual("uRepo_IContent_1000", key);
}
}