[ 
https://issues.apache.org/jira/browse/OAK-3003?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14640106#comment-14640106
 ] 

angela edited comment on OAK-3003 at 7/24/15 7:52 AM:
------------------------------------------------------

[~lbyrum], [[email protected]], from the top of my head i see the following 
options (without having looked at the feasibility):

# synchronous in Oak: add another {{Editor}} commit hook (or try to extend the 
existing {{UserValidator}} to clear/expire the cache of an individual user 
which has been added to a group. that looks a bit hacky to me as it wouldn't be 
consistent with with other group membership modification (e.g. group-group 
membership) ultimately leading to wrong expectations based on a behavior 
experienced in one case... for the sake of trying to keep the code base sane, i 
would rather not want to go this way.
# synchronous in Application: something similar could be done in the 
application layer by removing cache along with the modification to the group 
membership, where you already have the user at hand. obviously this makes the 
application knowledegable about some implementation details and would required 
that the editing session has sufficient permission on the user node). on the 
other hand it was exactly what you wish to do without any significant overhead 
for all other operations that are not affected... so, something like
{code}
Group group = ...
Authorizable toBeAdded = userManager.getAuthorizable(id);
if (toBeAdded != null) {
     group.addMember(toBeAdded);
     if (!toBeAdded.isGroup() && session.nodeExists(toBeAdded.getPath()) {
          Node userNode = session.getNode(toBeAdded.getPath())
          if (userNode.hasNode("rep:cache")) {
                userNode.getNode("rep:cache").remove(); // TODO: angela to 
verify that this really works
          }
    }
    session.save();
}
{code}
# assync in the Application: something similar could obviously be also achieved 
with an observation listener at the application layer. however, if the 
expiration time is set such that it covers just a few requests, it might well 
be that the asynchronous event handling (that needs to extract the changes made 
to a rep:members property, resolve the corresponding authorizables i.e. perform 
a query, test if it's really a user that has been added or removed... maybe not 
being able to find that user because it has been removed in the meantime...) 
just turns out to find no-cache at all or a cache that has expired in the 
meantime (because the user hasn't logged in in the mean time anyway). IMO there 
was a significant overhead with this solution compared to the one before with 
additionally coming with all the troubles that we keep experiencing with the 
event-based post-processing. and obviously that {{EventListener}} would know 
about the implementation details. so, my take is that there is no gain compared 
with the former proposal.
# assync in Oak with JMX: extending this patch with an implementation of 
{{RepositoryManagementMBean}} which would allow to force the invalidation of 
all or explicitly specified caches. the global invalidation would include a 
traversal of the complete user tree, which for sure isn't fast if the number of 
users is really big and might come with other drawbacks. also the need for 
"manually" triggering this global invalidation might not exactly be what you 
meant above and IMO it will suffer from the same problem as the observation 
listener: traversing the whole user tree to just find that the caches have been 
invalidated anyway in the mean time.

what I would like to suggest: would it be feasible for you to try the patch in 
your application with different expiration times configured to evaluate if the 
forced invalidation was really needed given the pros/cons i tried to list above?



was (Author: anchela):
[~lbyrum], [[email protected]], from the top of my head i see the following 
options (without having looked at the feasibility):

# synchronous in Oak: add another {{Editor}} commit hook (or try to extend the 
existing {{UserValidator}} to clear/expire the cache of an individual user 
which has been added to a group. that looks a bit hacky to me as it wouldn't be 
consistent with with other group membership modification (e.g. group-group 
membership) ultimately leading to wrong expectations based on a behavior 
experienced in one case... for the sake of trying to keep the code base sane, i 
would rather not want to go this way.
# synchronous in Application: something similar could be done in the 
application layer by removing cache along with the modification to the group 
membership, where you already have the user at hand. obviously this makes the 
application knowledegable about some implementation details and would required 
that the editing session has sufficient permission on the user node). on the 
other hand it was exactly what you wish to do without any significant overhead 
for all other operations that are not affected... so, something like
{code}
Group group = ...
Authorizable toBeAdded = userManager.getAuthorizable(id);
if (toBeAdded != null) {
     group.addMember(toBeAdded);
     if (!toBeAdded.isGroup() && session.nodeExists(toBeAdded.getPath()) {
          Node userNode = session.getNode(toBeAdded.getPath())
          if (userNode.hasNode("rep:cache")) {
                userNode.getNode("rep:cache").remove(); // TODO: angela to 
verify that this really works
          }
    }
    session.save();
}
# assync in the Application: something similar could obviously be also achieved 
with an observation listener at the application layer. however, if the 
expiration time is set such that it covers just a few requests, it might well 
be that the asynchronous event handling (that needs to extract the changes made 
to a rep:members property, resolve the corresponding authorizables i.e. perform 
a query, test if it's really a user that has been added or removed... maybe not 
being able to find that user because it has been removed in the meantime...) 
just turns out to find no-cache at all or a cache that has expired in the 
meantime (because the user hasn't logged in in the mean time anyway). IMO there 
was a significant overhead with this solution compared to the one before with 
additionally coming with all the troubles that we keep experiencing with the 
event-based post-processing. and obviously that {{EventListener}} would know 
about the implementation details. so, my take is that there is no gain compared 
with the former proposal.
# assync in Oak with JMX: extending this patch with an implementation of 
{{RepositoryManagementMBean}} which would allow to force the invalidation of 
all or explicitly specified caches. the global invalidation would include a 
traversal of the complete user tree, which for sure isn't fast if the number of 
users is really big and might come with other drawbacks. also the need for 
"manually" triggering this global invalidation might not exactly be what you 
meant above and IMO it will suffer from the same problem as the observation 
listener: traversing the whole user tree to just find that the caches have been 
invalidated anyway in the mean time.

what I would like to suggest: would it be feasible for you to try the patch in 
your application with different expiration times configured to evaluate if the 
forced invalidation was really needed given the pros/cons i tried to list above?


> Improve login performance with huge group membership
> ----------------------------------------------------
>
>                 Key: OAK-3003
>                 URL: https://issues.apache.org/jira/browse/OAK-3003
>             Project: Jackrabbit Oak
>          Issue Type: Improvement
>          Components: core
>            Reporter: angela
>            Assignee: angela
>         Attachments: OAK-3003.patch, group_cache_in_userprincipalprovider.txt
>
>
> As visible when running {{LoginWithMembershipTest}} default login performance 
> (which uses the {{o.a.j.oak.security.principal.PrincipalProviderImpl}} to 
> lookup the complete set of principals) suffers when a given user is member of 
> a huge number of groups (see also OAK-2690 for benchmark data).
> While using dynamic group membership (and thus a custom {{PrincipalProvider}} 
> would be the preferable way to deal with this, we still want to optimize 
> {{PrincipalProvider.getPrincipals(String userId}} for the default 
> implementation.
> With the introduction of a less generic implementation in OAK-2690, we might 
> be able to come up with an optimization that makes use of the very 
> implementation details of the user management while at the same time being 
> able to properly secure it as we won't need to extend the public API.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to