[
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)