Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DNN-8867: improving folder permission caching. #1532

Merged
merged 7 commits into from
Aug 29, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions DNN Platform/Library/Common/Utilities/DataCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Tabs;
using DotNetNuke.Instrumentation;
using DotNetNuke.Security.Permissions;
using DotNetNuke.Services.Cache;
using DotNetNuke.Services.Exceptions;
using DotNetNuke.Services.Log.EventLog;
Expand Down Expand Up @@ -190,7 +191,8 @@ public class DataCache
public const int FolderMappingCacheTimeOut = 20;
public const CacheItemPriority FolderMappingCachePriority = CacheItemPriority.High;

public const string FolderPermissionCacheKey = "FolderPermissions{0}";
public const string FolderPermissionCacheKey = "FolderPermissions{0}"; // parent cache dependency key
public const string FolderPathPermissionCacheKey = "FolderPathPermissions|{0}|{1}";
public const CacheItemPriority FolderPermissionCachePriority = CacheItemPriority.Normal;
public const int FolderPermissionCacheTimeOut = 20;

Expand Down Expand Up @@ -461,7 +463,8 @@ public static void ClearDesktopModulePermissionsCache()

public static void ClearFolderPermissionsCache(int PortalId)
{
RemoveCache(string.Format(FolderPermissionCacheKey, PortalId));
PermissionProvider.ResetCacheDependency(PortalId,
() => RemoveCache(string.Format(FolderPermissionCacheKey, PortalId)));
}

public static void ClearListsCache(int PortalId)
Expand Down
13 changes: 9 additions & 4 deletions DNN Platform/Library/Data/DataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1986,7 +1986,12 @@ public virtual IDataReader GetFolderPermissionsByPortal(int portalId)
return ExecuteReader("GetFolderPermissionsByPortal", GetNull(portalId));
}

public virtual void UpdateFolderPermission(int FolderPermissionID, int FolderID, int PermissionID, int roleID,
public virtual IDataReader GetFolderPermissionsByPortalAndPath(int portalId, string pathName)
{
return ExecuteReader("GetFolderPermissionsByPortalAndPath", GetNull(portalId), GetNull(pathName) ?? "");
}

public virtual void UpdateFolderPermission(int FolderPermissionID, int FolderID, int PermissionID, int roleID,
bool AllowAccess, int UserID, int lastModifiedByUserID)
{
ExecuteNonQuery("UpdateFolderPermission",
Expand All @@ -1999,11 +2004,11 @@ public virtual void UpdateFolderPermission(int FolderPermissionID, int FolderID,
lastModifiedByUserID);
}

#endregion
#endregion

#region DesktopModulePermission Methods
#region DesktopModulePermission Methods

public virtual int AddDesktopModulePermission(int portalDesktopModuleID, int permissionID, int roleID,
public virtual int AddDesktopModulePermission(int portalDesktopModuleID, int permissionID, int roleID,
bool allowAccess, int userID, int createdByUserID)
{
return ExecuteScalar<int>("AddDesktopModulePermission",
Expand Down
82 changes: 74 additions & 8 deletions DNN Platform/Library/Security/Permissions/PermissionProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Web.Services.Description;
using DotNetNuke.Collections.Internal;
using DotNetNuke.Common.Utilities;
using DotNetNuke.ComponentModel;
using DotNetNuke.Data;
Expand All @@ -34,6 +33,7 @@
using DotNetNuke.Entities.Tabs;
using DotNetNuke.Entities.Users;
using DotNetNuke.Security.Roles;
using DotNetNuke.Services.Cache;
using DotNetNuke.Services.Exceptions;
using DotNetNuke.Services.FileSystem;
using DotNetNuke.Services.Localization;
Expand Down Expand Up @@ -96,10 +96,50 @@ public static PermissionProvider Instance()
return ComponentFactory.GetComponent<PermissionProvider>();
}

private static SharedDictionary<int, DNNCacheDependency> _cacheDependencyDict = new SharedDictionary<int, DNNCacheDependency>();

private static DNNCacheDependency GetCacheDependency(int portalId)
{
DNNCacheDependency dependency;

// ReSharper disable once InconsistentlySynchronizedField
if (!_cacheDependencyDict.TryGetValue(portalId, out dependency))
{
lock (_cacheDependencyDict.GetWriteLock())
{
if (!_cacheDependencyDict.TryGetValue(portalId, out dependency))
{
var startAt = DateTime.UtcNow;
var cacheKey = string.Format(DataCache.FolderPermissionCacheKey, portalId);
DataCache.SetCache(cacheKey, portalId); // no expiration set for this
_cacheDependencyDict[portalId] =
dependency = new DNNCacheDependency(null, new[] { cacheKey }, startAt);
}
}
}
return dependency;
}

internal static void ResetCacheDependency(int portalId, Action cacehClearAction)
{
lock (_cacheDependencyDict.GetWriteLock())
{
// first execute the cache clear action then check the dependency change
cacehClearAction.Invoke();
DNNCacheDependency dependency;
if (_cacheDependencyDict.TryGetValue(portalId, out dependency))
{
_cacheDependencyDict.Remove(portalId);
dependency.Dispose();
}
}
}

#endregion

#region Private Methods

#if false
private object GetFolderPermissionsCallBack(CacheItemArgs cacheItemArgs)
{
var PortalID = (int)cacheItemArgs.ParamList[0];
Expand Down Expand Up @@ -153,6 +193,7 @@ private Dictionary<string, FolderPermissionCollection> GetFolderPermissions(int
CBO.GetCachedObject<Dictionary<string, FolderPermissionCollection>>(
new CacheItemArgs(cacheKey, DataCache.FolderPermissionCacheTimeOut, DataCache.FolderPermissionCachePriority, PortalID), GetFolderPermissionsCallBack);
}
#endif

/// -----------------------------------------------------------------------------
/// <summary>
Expand Down Expand Up @@ -423,7 +464,7 @@ private IEnumerable<RoleInfo> DefaultImplicitRoles(int portalId)
};
}

#endregion
#endregion

#region Protected Methods

Expand Down Expand Up @@ -540,6 +581,7 @@ public virtual void DeleteFolderPermissionsByUser(UserInfo objUser)

public virtual FolderPermissionCollection GetFolderPermissionsCollectionByFolder(int PortalID, string Folder)
{
#if fale
string dictionaryKey = Folder;
if (string.IsNullOrEmpty(dictionaryKey))
{
Expand All @@ -557,6 +599,34 @@ public virtual FolderPermissionCollection GetFolderPermissionsCollectionByFolder
folderPermissions = new FolderPermissionCollection();
}
return folderPermissions;
#else
var cacheKey = string.Format(DataCache.FolderPathPermissionCacheKey, PortalID, Folder);
return CBO.GetCachedObject<FolderPermissionCollection>(
new CacheItemArgs(cacheKey, DataCache.FolderPermissionCacheTimeOut, DataCache.FolderPermissionCachePriority)
{
CacheDependency = GetCacheDependency(PortalID)
},
_ =>
{
var collection = new FolderPermissionCollection();
try
{
using (var dr = dataProvider.GetFolderPermissionsByPortalAndPath(PortalID, Folder))
{
while (dr.Read())
{
var folderPermissionInfo = CBO.FillObject<FolderPermissionInfo>(dr, false);
collection.Add(folderPermissionInfo);
}
}
}
catch (Exception exc)
{
Exceptions.LogException(exc);
}
return collection;
});
#endif
}

public virtual bool HasFolderPermission(FolderPermissionCollection objFolderPermissions, string PermissionKey)
Expand Down Expand Up @@ -828,11 +898,7 @@ public virtual bool HasModuleAccess(SecurityAccessLevel accessLevel, string perm
else
{
// Need to check if it was denied at Tab level
if (IsDeniedTabPermission(tab, "CONTENT,EDIT"))
{
isAuthorized = false;
}
else
if (!IsDeniedTabPermission(tab, "CONTENT,EDIT"))
{
isAuthorized = HasModulePermission(moduleConfiguration, permissionKey);
}
Expand Down
6 changes: 4 additions & 2 deletions DNN Platform/Library/Services/Cache/CachingProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
using DotNetNuke.Entities.Portals;
using DotNetNuke.Entities.Tabs;
using DotNetNuke.Instrumentation;
using DotNetNuke.Security.Permissions;
using DotNetNuke.Services.Localization;

#endregion
Expand Down Expand Up @@ -209,8 +210,9 @@ private void ClearFolderCacheInternal(int portalId, bool clearRuntime)
// here so we remove them using a prefix
var folderUserCachePrefix = GetCacheKey(string.Format("Folders|{0}|", portalId));
ClearCacheInternal(folderUserCachePrefix, clearRuntime);

RemoveFormattedCacheKey(DataCache.FolderPermissionCacheKey, clearRuntime, portalId);

PermissionProvider.ResetCacheDependency(portalId,
() => RemoveFormattedCacheKey(DataCache.FolderPermissionCacheKey, clearRuntime, portalId));
}

private void ClearHostCacheInternal(bool clearRuntime)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,23 @@ UPDATE {databaseOwner}{objectQualifier}Packages SET Version = @version WHERE Nam

GO

IF object_id(N'{databaseOwner}[{objectQualifier}GetFolderPermissionsByPortalAndPath]', 'P') IS NOT NULL
DROP PROCEDURE {databaseOwner}[{objectQualifier}GetFolderPermissionsByPortalAndPath]
GO

CREATE PROCEDURE {databaseOwner}[{objectQualifier}GetFolderPermissionsByPortalAndPath]
@PortalId int,
@FolderPath nvarchar(300)
AS
BEGIN
SET @PortalId = IsNull(@PortalId, -1)

SELECT *
FROM {databaseOwner}[{objectQualifier}vw_FolderPermissions]
WHERE PortalID = @PortalId AND (FolderPath = @FolderPath OR @FolderPath IS NULL)
END
GO

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'{databaseOwner}[{objectQualifier}GetAllFiles]') AND type in (N'P', N'PC'))
DROP PROCEDURE {databaseOwner}[{objectQualifier}GetAllFiles]
GO
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
/***** *****/
/************************************************************/



/************************************************************/
/***** SqlDataProvider *****/
/************************************************************/