From 70e438a510e609eabf08c8248b2fb5e73b5bafdd Mon Sep 17 00:00:00 2001 From: Louis DeJardin Date: Mon, 6 Dec 2010 14:36:38 -0800 Subject: [PATCH] PERF: Cache role and permission Fixes http://orchard.codeplex.com/workitem/16888 --HG-- branch : perf --- .../Roles/Services/RoleServiceTests.cs | 54 ++++++++++++++++++- .../Orchard.Roles/Services/IRoleService.cs | 2 + .../Orchard.Roles/Services/RoleService.cs | 44 +++++++++++++-- .../RolesBasedAuthorizationService.cs | 5 +- 4 files changed, 96 insertions(+), 9 deletions(-) diff --git a/src/Orchard.Tests.Modules/Roles/Services/RoleServiceTests.cs b/src/Orchard.Tests.Modules/Roles/Services/RoleServiceTests.cs index 07b7488ec..4138b2796 100644 --- a/src/Orchard.Tests.Modules/Roles/Services/RoleServiceTests.cs +++ b/src/Orchard.Tests.Modules/Roles/Services/RoleServiceTests.cs @@ -3,14 +3,35 @@ using System.Collections.Generic; using System.Linq; using Autofac; using NUnit.Framework; +using Orchard.Caching; +using Orchard.Environment.Extensions.Models; using Orchard.Roles.Models; using Orchard.Roles.Services; +using Orchard.Security.Permissions; +using Orchard.Tests.Stubs; namespace Orchard.Tests.Modules.Roles.Services { [TestFixture] - public class RoleServiceTests : DatabaseEnabledTestsBase{ + public class RoleServiceTests : DatabaseEnabledTestsBase { public override void Register(ContainerBuilder builder) { builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + } + + public class TestPermissionProvider : IPermissionProvider { + public Feature Feature { + get { return new Feature { Descriptor = new FeatureDescriptor { Id = "RoleServiceTests" } }; } + } + + public IEnumerable GetPermissions() { + return "alpha,beta,gamma,delta".Split(',').Select(name => new Permission { Name = name }); + } + + public IEnumerable GetDefaultStereotypes() { + return Enumerable.Empty(); + } } protected override IEnumerable DatabaseTypes { @@ -34,5 +55,36 @@ namespace Orchard.Tests.Modules.Roles.Services { Assert.That(roles, Has.Some.Property("Name").EqualTo("two")); Assert.That(roles, Has.Some.Property("Name").EqualTo("three")); } + + [Test] + public void PermissionChangesShouldBeVisibleImmediately() { + + var service = _container.Resolve(); + + ClearSession(); + { + service.CreateRole("test"); + var roleId = service.GetRoleByName("test").Id; + service.UpdateRole(roleId, "test", new[] { "alpha", "beta", "gamma" }); + } + + ClearSession(); + { + var result = service.GetPermissionsForRoleByName("test"); + Assert.That(result.Count(), Is.EqualTo(3)); + } + + ClearSession(); + { + var roleId = service.GetRoleByName("test").Id; + service.UpdateRole(roleId, "test", new[] { "alpha", "beta", "gamma", "delta" }); + } + + ClearSession(); + { + var result = service.GetPermissionsForRoleByName("test"); + Assert.That(result.Count(), Is.EqualTo(4)); + } + } } } diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Services/IRoleService.cs b/src/Orchard.Web/Modules/Orchard.Roles/Services/IRoleService.cs index dddcb79d4..732d5d53f 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Services/IRoleService.cs +++ b/src/Orchard.Web/Modules/Orchard.Roles/Services/IRoleService.cs @@ -13,5 +13,7 @@ namespace Orchard.Roles.Services { void DeleteRole(int id); IDictionary> GetInstalledPermissions(); IEnumerable GetPermissionsForRole(int id); + + IEnumerable GetPermissionsForRoleByName(string name); } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Services/RoleService.cs b/src/Orchard.Web/Modules/Orchard.Roles/Services/RoleService.cs index 9e6815a38..fe9b94ca8 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Services/RoleService.cs +++ b/src/Orchard.Web/Modules/Orchard.Roles/Services/RoleService.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; +using Orchard.Caching; using Orchard.Data; using Orchard.Localization; using Orchard.Logging; @@ -11,16 +12,24 @@ using Orchard.Security.Permissions; namespace Orchard.Roles.Services { [UsedImplicitly] public class RoleService : IRoleService { + private const string SignalName = "Orchard.Roles.Services.RoleService"; + private readonly IRepository _roleRepository; private readonly IRepository _permissionRepository; private readonly IEnumerable _permissionProviders; + private readonly ICacheManager _cacheManager; + private readonly ISignals _signals; public RoleService(IRepository roleRepository, IRepository permissionRepository, - IEnumerable permissionProviders) { + IEnumerable permissionProviders, + ICacheManager cacheManager, + ISignals signals) { _roleRepository = roleRepository; _permissionRepository = permissionRepository; _permissionProviders = permissionProviders; + _cacheManager = cacheManager; + _signals = signals; Logger = NullLogger.Instance; T = NullLocalizer.Instance; } @@ -43,6 +52,7 @@ namespace Orchard.Roles.Services { public void CreateRole(string roleName) { _roleRepository.Create(new RoleRecord { Name = roleName }); + TriggerSignal(); } public void CreatePermissionForRole(string roleName, string permissionName) { @@ -56,6 +66,7 @@ namespace Orchard.Roles.Services { RoleRecord roleRecord = GetRoleByName(roleName); PermissionRecord permissionRecord = _permissionRepository.Get(x => x.Name == permissionName); roleRecord.RolesPermissions.Add(new RolesPermissionsRecord { Permission = permissionRecord, Role = roleRecord }); + TriggerSignal(); } public void UpdateRole(int id, string roleName, IEnumerable rolePermissions) { @@ -73,6 +84,7 @@ namespace Orchard.Roles.Services { } PermissionRecord permissionRecord = _permissionRepository.Get(x => x.Name == permission); roleRecord.RolesPermissions.Add(new RolesPermissionsRecord { Permission = permissionRecord, Role = roleRecord }); + TriggerSignal(); } } @@ -100,6 +112,7 @@ namespace Orchard.Roles.Services { public void DeleteRole(int id) { _roleRepository.Delete(GetRole(id)); + TriggerSignal(); } public IDictionary> GetInstalledPermissions() { @@ -107,13 +120,13 @@ namespace Orchard.Roles.Services { foreach (var permissionProvider in _permissionProviders) { var featureName = permissionProvider.Feature.Descriptor.Id; var permissions = permissionProvider.GetPermissions(); - foreach(var permission in permissions) { + foreach (var permission in permissions) { var category = permission.Category; string title = String.IsNullOrWhiteSpace(category) ? T("{0} Feature", featureName).Text : T(category).Text; - if ( installedPermissions.ContainsKey(title) ) - installedPermissions[title] = installedPermissions[title].Concat( new [] {permission} ); + if (installedPermissions.ContainsKey(title)) + installedPermissions[title] = installedPermissions[title].Concat(new[] { permission }); else installedPermissions.Add(title, new[] { permission }); } @@ -130,5 +143,28 @@ namespace Orchard.Roles.Services { } return permissions; } + + public IEnumerable GetPermissionsForRoleByName(string name) { + return _cacheManager.Get(name, ctx => { + MonitorSignal(ctx); + return GetPermissionsForRoleByNameInner(name); + }); + } + + IEnumerable GetPermissionsForRoleByNameInner(string name) { + var roleRecord = GetRoleByName(name); + if (roleRecord == null) + return Enumerable.Empty(); + return GetPermissionsForRole(roleRecord.Id); + } + + + private void MonitorSignal(AcquireContext ctx) { + ctx.Monitor(_signals.When(SignalName)); + } + + private void TriggerSignal() { + _signals.Trigger(SignalName); + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Services/RolesBasedAuthorizationService.cs b/src/Orchard.Web/Modules/Orchard.Roles/Services/RolesBasedAuthorizationService.cs index 67aceaa7d..1f8d67b2b 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Services/RolesBasedAuthorizationService.cs +++ b/src/Orchard.Web/Modules/Orchard.Roles/Services/RolesBasedAuthorizationService.cs @@ -71,10 +71,7 @@ namespace Orchard.Roles.Services { } foreach (var role in rolesToExamine) { - RoleRecord roleRecord = _roleService.GetRoleByName(role); - if ( roleRecord == null ) - continue; - foreach (var permissionName in _roleService.GetPermissionsForRole(roleRecord.Id)) { + foreach (var permissionName in _roleService.GetPermissionsForRoleByName(role)) { string possessedName = permissionName; if (grantingNames.Any(grantingName => String.Equals(possessedName, grantingName, StringComparison.OrdinalIgnoreCase))) { context.Granted = true;