From 6d95b87f34c89e9f542ea5e923e5942371abc23d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Halil=20=C4=B0brahim=20Kalkan?= Date: Wed, 17 Aug 2022 18:15:36 +0300 Subject: [PATCH] Handle initial null situation for permission definition cache stamp --- .../DynamicPermissionDefinitionStore.cs | 76 ++++++++++++++++--- 1 file changed, 65 insertions(+), 11 deletions(-) diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs index 2186ae56cf..0e8b28d38e 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Options; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; +using Volo.Abp.DistributedLocking; using Volo.Abp.Threading; namespace Volo.Abp.PermissionManagement; @@ -18,6 +19,7 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor protected IPermissionDefinitionSerializer PermissionDefinitionSerializer { get; } protected IDynamicPermissionDefinitionStoreInMemoryCache StoreCache { get; } protected IDistributedCache DistributedCache { get; } + protected IAbpDistributedLock DistributedLock { get; } public PermissionManagementOptions PermissionManagementOptions { get; } protected AbpDistributedCacheOptions CacheOptions { get; } @@ -28,13 +30,15 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor IDynamicPermissionDefinitionStoreInMemoryCache storeCache, IDistributedCache distributedCache, IOptions cacheOptions, - IOptions permissionManagementOptions) + IOptions permissionManagementOptions, + IAbpDistributedLock distributedLock) { PermissionGroupRepository = permissionGroupRepository; PermissionRepository = permissionRepository; PermissionDefinitionSerializer = permissionDefinitionSerializer; StoreCache = storeCache; DistributedCache = distributedCache; + DistributedLock = distributedLock; PermissionManagementOptions = permissionManagementOptions.Value; CacheOptions = cacheOptions.Value; } @@ -80,26 +84,76 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor using (await StoreCache.SyncSemaphore.LockAsync()) { - var cacheKey = GetCacheKey(); - - var stampInDistributedCache = await DistributedCache.GetStringAsync(cacheKey); - - if (StoreCache.CacheStamp == stampInDistributedCache) + var stampInDistributedCache = await GetOrSetStampInDistributedCache(); + + if (stampInDistributedCache == StoreCache.CacheStamp) { return; } - var permissionGroupRecords = await PermissionGroupRepository.GetListAsync(); - var permissionRecords = await PermissionRepository.GetListAsync(); - - await StoreCache.FillAsync(permissionGroupRecords, permissionRecords); + await UpdateInMemoryStoreCache(); StoreCache.CacheStamp = stampInDistributedCache; } } - private string GetCacheKey() + private async Task UpdateInMemoryStoreCache() + { + var permissionGroupRecords = await PermissionGroupRepository.GetListAsync(); + var permissionRecords = await PermissionRepository.GetListAsync(); + + await StoreCache.FillAsync(permissionGroupRecords, permissionRecords); + } + + private async Task GetOrSetStampInDistributedCache() + { + var cacheKey = GetCommonStampCacheKey(); + + var stampInDistributedCache = await DistributedCache.GetStringAsync(cacheKey); + if (stampInDistributedCache != null) + { + return stampInDistributedCache; + } + + await using (var commonLockHandle = await DistributedLock + .TryAcquireAsync(GetCommonDistributedLockKey(), TimeSpan.FromMinutes(2))) + { + if (commonLockHandle == null) + { + /* This request will fail */ + throw new AbpException( + "Could not acquire distributed lock for permission definition common stamp check!" + ); + } + + stampInDistributedCache = await DistributedCache.GetStringAsync(cacheKey); + if (stampInDistributedCache != null) + { + return stampInDistributedCache; + } + + stampInDistributedCache = Guid.NewGuid().ToString(); + + await DistributedCache.SetStringAsync( + cacheKey, + stampInDistributedCache, + new DistributedCacheEntryOptions + { + SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable? + } + ); + } + + return stampInDistributedCache; + } + + private string GetCommonStampCacheKey() { return $"{CacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp"; } + + private string GetCommonDistributedLockKey() + { + return $"{CacheOptions.KeyPrefix}_Common_AbpPermissionUpdateLock"; + } } \ No newline at end of file