Browse Source

Optimize batch state checker model lookup from O(N²) to O(N)

Replace linear scans with Dictionary/HashSet lookups in both
RequirePermissionsSimpleBatchStateChecker and
RequireFeaturesSimpleBatchStateChecker for consistency.
pull/25276/head
maliming 6 months ago
parent
commit
6505dc0d20
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 28
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RequirePermissionsSimpleBatchStateChecker.cs
  2. 30
      framework/src/Volo.Abp.Features/Volo/Abp/Features/RequireFeaturesSimpleBatchStateChecker.cs

28
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RequirePermissionsSimpleBatchStateChecker.cs

@ -47,13 +47,33 @@ public class RequirePermissionsSimpleBatchStateChecker<TState> : SimpleBatchStat
var result = new SimpleStateCheckerResult<TState>(context.States);
var permissions = _models.Where(x => context.States.Any(s => s.Equals(x.State))).SelectMany(x => x.Permissions).Distinct().ToArray();
var grantResult = await permissionChecker.IsGrantedAsync(permissions);
var stateSet = new HashSet<TState>(context.States);
var modelLookup = new Dictionary<TState, RequirePermissionsSimpleBatchStateCheckerModel<TState>>();
var allPermissions = new HashSet<string>();
foreach (var model in _models)
{
if (!stateSet.Contains(model.State))
{
continue;
}
if (!modelLookup.ContainsKey(model.State))
{
modelLookup[model.State] = model;
}
foreach (var permission in model.Permissions)
{
allPermissions.Add(permission);
}
}
var grantResult = await permissionChecker.IsGrantedAsync(allPermissions.ToArray());
foreach (var state in context.States)
{
var model = _models.FirstOrDefault(x => x.State.Equals(state));
if (model != null)
if (modelLookup.TryGetValue(state, out var model))
{
if (model.RequiresAll)
{

30
framework/src/Volo.Abp.Features/Volo/Abp/Features/RequireFeaturesSimpleBatchStateChecker.cs

@ -49,17 +49,33 @@ public class RequireFeaturesSimpleBatchStateChecker<TState> : SimpleBatchStateCh
var result = new SimpleStateCheckerResult<TState>(context.States);
var relevantModels = _models
.Where(x => context.States.Any(s => s.Equals(x.State)))
.ToList();
var stateSet = new HashSet<TState>(context.States);
var modelLookup = new Dictionary<TState, RequireFeaturesSimpleBatchStateCheckerModel<TState>>();
var allFeatures = new HashSet<string>();
var features = relevantModels.SelectMany(x => x.FeatureNames).Distinct().ToArray();
var featureValues = await featureChecker.IsEnabledAsync(features);
foreach (var model in _models)
{
if (!stateSet.Contains(model.State))
{
continue;
}
if (!modelLookup.ContainsKey(model.State))
{
modelLookup[model.State] = model;
}
foreach (var featureName in model.FeatureNames)
{
allFeatures.Add(featureName);
}
}
var featureValues = await featureChecker.IsEnabledAsync(allFeatures.ToArray());
foreach (var state in context.States)
{
var model = relevantModels.FirstOrDefault(x => x.State.Equals(state));
if (model != null)
if (modelLookup.TryGetValue(state, out var model))
{
if (model.RequiresAll)
{

Loading…
Cancel
Save