A bunch of minor performance optimizations (#16335)

* Do not execute query if no macros found

* Request cache the permission lookup

* Unbreak change by adding obsolete ctor

* Clean up

* Wrap indexing for delivery API in a scope

* Do not ask options every time for the timeout, instead listen for updates

* Lookup content types once instead of one by one

* Use TryGetValue instead

* Do a distinct on user ids before building index, to avoid issue with more than 2100 parameters

* Don't map ContentDto (it's unused)

* Introduce request bound block editor element cache

---------

Co-authored-by: kjac <kja@umbraco.dk>
This commit is contained in:
Bjarke Berg
2024-06-03 11:23:25 +02:00
committed by GitHub
parent 528583430f
commit 0aaac78cfa
21 changed files with 210 additions and 97 deletions

View File

@@ -1,9 +1,12 @@
using System.Data.Common;
using System.Globalization;
using System.Linq.Expressions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Notifications;
@@ -25,8 +28,11 @@ internal class UserService : RepositoryService, IUserService
private readonly ILogger<UserService> _logger;
private readonly IRuntimeState _runtimeState;
private readonly IUserGroupRepository _userGroupRepository;
private readonly IRequestCache _requestCache;
private readonly IUserRepository _userRepository;
[Obsolete("Use non-obsolete constructor. This will be removed in Umbraco 15.")]
public UserService(
ICoreScopeProvider provider,
ILoggerFactory loggerFactory,
@@ -35,11 +41,26 @@ internal class UserService : RepositoryService, IUserService
IUserRepository userRepository,
IUserGroupRepository userGroupRepository,
IOptions<GlobalSettings> globalSettings)
: this(provider, loggerFactory, eventMessagesFactory, runtimeState, userRepository, userGroupRepository, globalSettings, StaticServiceProvider.Instance.GetRequiredService<IRequestCache>())
{
}
public UserService(
ICoreScopeProvider provider,
ILoggerFactory loggerFactory,
IEventMessagesFactory eventMessagesFactory,
IRuntimeState runtimeState,
IUserRepository userRepository,
IUserGroupRepository userGroupRepository,
IOptions<GlobalSettings> globalSettings,
IRequestCache requestCache)
: base(provider, loggerFactory, eventMessagesFactory)
{
_runtimeState = runtimeState;
_userRepository = userRepository;
_userGroupRepository = userGroupRepository;
_requestCache = requestCache;
_globalSettings = globalSettings.Value;
_logger = loggerFactory.CreateLogger<UserService>();
}
@@ -1125,17 +1146,23 @@ internal class UserService : RepositoryService, IUserService
/// <param name="path">Path to check permissions for</param>
public EntityPermissionSet GetPermissionsForPath(IUser? user, string? path)
{
var nodeIds = path?.GetIdsFromPathReversed();
if (nodeIds is null || nodeIds.Length == 0 || user is null)
var result = (EntityPermissionSet?)_requestCache.Get($"{nameof(GetPermissionsForPath)}|{path}|{user?.Id}", () =>
{
return EntityPermissionSet.Empty();
}
var nodeIds = path?.GetIdsFromPathReversed();
// collect all permissions structures for all nodes for all groups belonging to the user
EntityPermission[] groupPermissions = GetPermissionsForPath(user.Groups.ToArray(), nodeIds, true).ToArray();
if (nodeIds is null || nodeIds.Length == 0 || user is null)
{
return EntityPermissionSet.Empty();
}
// collect all permissions structures for all nodes for all groups belonging to the user
EntityPermission[] groupPermissions = GetPermissionsForPath(user.Groups.ToArray(), nodeIds, true).ToArray();
return CalculatePermissionsForPathForUser(groupPermissions, nodeIds);
});
return result ?? EntityPermissionSet.Empty();
return CalculatePermissionsForPathForUser(groupPermissions, nodeIds);
}
/// <summary>