-
Notifications
You must be signed in to change notification settings - Fork 153
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
Performance: Cache RoleMaps produced by RoleMap#newMatchingRoleMap()
#81
Performance: Cache RoleMaps produced by RoleMap#newMatchingRoleMap()
#81
Conversation
Since the newMatchingRoleMap is called for every ACL request and a lot of permissions are checked for a project when the home page loads, having a cache avoids checking regular expressions again for every time permission checks are called for a given Item.
RoleMap#newMatchingRoleMap()
RoleMap#newMatchingRoleMap()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be great to think about cache invalidation.
I would guess that ItemListener
would be enough for it (so that we invalidate the cache on item creation or deletion). WDYT?
Also, would be great to have some performance metrics before and after the change from our benchmarks
* for different permissions for the same {@code itemName}, so cache them and avoid wasting time | ||
* matching regular expressions. | ||
*/ | ||
private final Cache<String, RoleMap> matchingRoleMapCache = CacheBuilder.newBuilder() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is fine to use Guava as long as we do not needed newer versions.
Maybe we could have a research task for comparing cache implementations with benchmarks in later phases
Results compared to the benchmarks carried out in #80 : |
* cleanup JavaDoc for newMatchingRoleMap * remove unused private method * cleanup unAssignRole
*/ | ||
public RoleMap newMatchingRoleMap(String namePattern) { | ||
RoleMap cachedRoleMap = matchingRoleMapCache.getIfPresent(namePattern); | ||
public RoleMap newMatchingRoleMap(String itemName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed the JavaDoc because I don't think it was correctly telling what was going on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that the original Javadoc was wrong,
Maybe we could rename it to itemNamePrefix
or so, because actually it does some kind of "pattern matching", just not the regexp/wildcard/whatever. It just takes a string and verifies it against regexp, but it does not really have to be a full item name. For better or worse...
* @param permission The permission you want to check | ||
* @return A Set of Roles holding the given permission | ||
*/ | ||
private Set<Role> getRolesHavingPermission(final Permission permission) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed it because it was not being used anywhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was refactored out in #54 and has no references to it now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like a good API method, but we can always recover it later if somebody needs it
@@ -203,8 +203,8 @@ public SidACL getACL(RoleType roleType, AccessControlled controlledItem) { | |||
public void addRole(Role role) { | |||
if (this.getRole(role.getName()) == null) { | |||
this.grantedRoles.put(role, new CopyOnWriteArraySet<>()); | |||
matchingRoleMapCache.invalidateAll(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This cache would only be affected when a change to grantedRoles
is made because the RoleMap
returned contains only those roles applicable for a given name. So it won't be necessary to use ItemListener
in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fine with me, just minor comments
* for different permissions for the same {@code itemName}, so cache them and avoid wasting time | ||
* matching regular expressions. | ||
*/ | ||
private final Cache<String, RoleMap> matchingRoleMapCache = CacheBuilder.newBuilder() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is fine to use Guava as long as we do not needed newer versions.
Maybe we could have a research task for comparing cache implementations with benchmarks in later phases
src/main/java/com/michelin/cio/hudson/plugins/rolestrategy/RoleMap.java
Outdated
Show resolved
Hide resolved
@@ -203,8 +203,8 @@ public SidACL getACL(RoleType roleType, AccessControlled controlledItem) { | |||
public void addRole(Role role) { | |||
if (this.getRole(role.getName()) == null) { | |||
this.grantedRoles.put(role, new CopyOnWriteArraySet<>()); | |||
matchingRoleMapCache.invalidateAll(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed
* @param permission The permission you want to check | ||
* @return A Set of Roles holding the given permission | ||
*/ | ||
private Set<Role> getRolesHavingPermission(final Permission permission) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like a good API method, but we can always recover it later if somebody needs it
67fb6a0
to
b267c97
Compare
Test failure is really odd here, and last reopen did not trigger the build. Let me try |
*/ | ||
private final Cache<String, RoleMap> matchingRoleMapCache = CacheBuilder.newBuilder() | ||
.softValues() | ||
.maximumSize(Settings.USER_DETAILS_CACHE_MAX_SIZE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default value for the max size of the cache is 100. If there are more than 100 objects managed by Role Strategy, the cache would start evicting entries. Also, the max size of the cache cannot be increased after its creation. Should we care about this situation and create a larger cache using an ItemListener
and a ComputerListener
at the cost of higher memory usage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1. The objects are not big, so bumping to 2048 or so would make sense
* for different permissions for the same {@code itemNamePrefix}, so cache them and avoid wasting time | ||
* matching regular expressions. | ||
*/ | ||
private final Cache<String, RoleMap> matchingRoleMapCache = CacheBuilder.newBuilder() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The matching RoleMaps that are created also have a cache in them which is not needed. Do we reorganize the class structure to avoid it or don't care about a little more memory use?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would submit a follow-up ticket for it. Memory usage is not a problem for the plugin ATM
RoleMap#newMatchingRoleMap()
RoleMap#newMatchingRoleMap()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
re-:+1:
Hi. This has some really odd implication as it seems. A typical workflow is:
But role assignment doesn't invalidate the cache and hence, the user sticks with his old roleset for an hour. |
I plan to cut a releas soon, sorry for delays
…On Fri, Aug 28, 2020, 18:09 Odilon Alves ***@***.***> wrote:
Yeah, facing the same issue mentioned by @scrwr <https://github.com/scrwr>
here
<#81 (comment)>
.
There is any command that i can run to invalidate cache? Maybe in Jenkins
Script Console?
—
You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub
<#81 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAW4RIEJVMV7SXDLRRFZA23SC7JCVANCNFSM4HZQA4CA>
.
|
@odilontalk I just ran into this myself and confirmed (as implied by @scrwr's comment) that creating a new arbitrary dummy role and hitting "apply" will clear/update the cached permissions. You can then delete that role. |
From our discussion yesterday on the Gitter chat and since the newMatchingRoleMap is called for every ACL request and a lot of permissions are checked for a project when the home page loads, having a cache avoids checking regular expressions again for every time permission checks are called for a given Item.