Browse Source

Index batch state checker models by state for O(1) lookup

- Mirror _models with Dictionary<TState, ...> populated in AddCheckModels
- GetModelOrNull goes through the dict, matching IsEnabledAsync's first-wins
- Pin first-wins via a regression test
pull/25424/head
maliming 1 week ago
parent
commit
340bd51f49
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 12
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RequirePermissionsSimpleBatchStateChecker.cs
  2. 12
      framework/src/Volo.Abp.Features/Volo/Abp/Features/RequireFeaturesSimpleBatchStateChecker.cs
  3. 17
      framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/RequireFeaturesSimpleBatchStateChecker_Tests.cs

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

@ -27,9 +27,12 @@ public class RequirePermissionsSimpleBatchStateChecker<TState> : SimpleBatchStat
private readonly List<RequirePermissionsSimpleBatchStateCheckerModel<TState>> _models;
private readonly Dictionary<TState, RequirePermissionsSimpleBatchStateCheckerModel<TState>> _modelsByState;
public RequirePermissionsSimpleBatchStateChecker()
{
_models = new List<RequirePermissionsSimpleBatchStateCheckerModel<TState>>();
_modelsByState = new Dictionary<TState, RequirePermissionsSimpleBatchStateCheckerModel<TState>>();
}
public RequirePermissionsSimpleBatchStateChecker<TState> AddCheckModels(params RequirePermissionsSimpleBatchStateCheckerModel<TState>[] models)
@ -37,6 +40,13 @@ public class RequirePermissionsSimpleBatchStateChecker<TState> : SimpleBatchStat
Check.NotNullOrEmpty(models, nameof(models));
_models.AddRange(models);
foreach (var model in models)
{
if (!_modelsByState.ContainsKey(model.State))
{
_modelsByState[model.State] = model;
}
}
return this;
}
@ -49,7 +59,7 @@ public class RequirePermissionsSimpleBatchStateChecker<TState> : SimpleBatchStat
public virtual RequirePermissionsSimpleBatchStateCheckerModel<TState>? GetModelOrNull(TState state)
{
return _models.FirstOrDefault(m => EqualityComparer<TState>.Default.Equals(m.State, state));
return _modelsByState.TryGetValue(state, out var model) ? model : null;
}
public override async Task<SimpleStateCheckerResult<TState>> IsEnabledAsync(SimpleBatchStateCheckerContext<TState> context)

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

@ -27,9 +27,12 @@ public class RequireFeaturesSimpleBatchStateChecker<TState> : SimpleBatchStateCh
private readonly List<RequireFeaturesSimpleBatchStateCheckerModel<TState>> _models;
private readonly Dictionary<TState, RequireFeaturesSimpleBatchStateCheckerModel<TState>> _modelsByState;
public RequireFeaturesSimpleBatchStateChecker()
{
_models = new List<RequireFeaturesSimpleBatchStateCheckerModel<TState>>();
_modelsByState = new Dictionary<TState, RequireFeaturesSimpleBatchStateCheckerModel<TState>>();
}
public RequireFeaturesSimpleBatchStateChecker<TState> AddCheckModels(
@ -38,6 +41,13 @@ public class RequireFeaturesSimpleBatchStateChecker<TState> : SimpleBatchStateCh
Check.NotNullOrEmpty(models, nameof(models));
_models.AddRange(models);
foreach (var model in models)
{
if (!_modelsByState.ContainsKey(model.State))
{
_modelsByState[model.State] = model;
}
}
return this;
}
@ -50,7 +60,7 @@ public class RequireFeaturesSimpleBatchStateChecker<TState> : SimpleBatchStateCh
public virtual RequireFeaturesSimpleBatchStateCheckerModel<TState>? GetModelOrNull(TState state)
{
return _models.FirstOrDefault(x => EqualityComparer<TState>.Default.Equals(x.State, state));
return _modelsByState.TryGetValue(state, out var model) ? model : null;
}
public override async Task<SimpleStateCheckerResult<TState>> IsEnabledAsync(

17
framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/RequireFeaturesSimpleBatchStateChecker_Tests.cs

@ -85,6 +85,23 @@ public class RequireFeaturesSimpleBatchStateChecker_Tests : FeatureTestBase
}
}
[Fact]
public void GetModelOrNull_Returns_First_Win_When_Same_State_Registered_Twice()
{
// Mirrors IsEnabledAsync's modelLookup behaviour: when the same state is registered
// multiple times, the first registration wins. Backed by the dictionary index.
var checker = new RequireFeaturesSimpleBatchStateChecker<NamedState>();
var state = new NamedState("A");
checker.AddCheckModels(
new RequireFeaturesSimpleBatchStateCheckerModel<NamedState>(state, new[] { "First" }, true));
checker.AddCheckModels(
new RequireFeaturesSimpleBatchStateCheckerModel<NamedState>(state, new[] { "Second" }, true));
checker.GetModelOrNull(state)!.FeatureNames.ShouldBe(new[] { "First" });
}
[Fact]
public void GetModelOrNull_Uses_Same_Equality_As_Runtime()
{

Loading…
Cancel
Save