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

Expensive reindex when local roles are deleted #140

Open
ewohnlich opened this issue Jun 18, 2024 · 4 comments
Open

Expensive reindex when local roles are deleted #140

ewohnlich opened this issue Jun 18, 2024 · 4 comments

Comments

@ewohnlich
Copy link
Contributor

https://github.com/zopefoundation/Products.CMFCore/blob/master/src/Products/CMFCore/MembershipTool.py#L457 This method handles local role removal in a variety of cases but I am probably interested in the process of deleting a user. CMFPlone.controlpanel.browser.usergroups_usersoverview calls this method with recursive=True. So what appears to be happening is that the entire site is traversed when a user is deleted and each of those objects calls reindexObjectSecurity. This happens even if the user has no local roles.

What I did:

Deleted a user with no local roles

What I expect to happen:

Receiver a response in a reasonable amount of time.

What actually happened:

Response took a VERY long time to be received.

What version of Python and Zope/Addons I am using:

None

Proposal

  1. I think the reindex section can be moved into this condition https://github.com/zopefoundation/Products.CMFCore/blob/master/src/Products/CMFCore/MembershipTool.py#L463 so that it only happens if there are actually local roles to delete. This saved a significant amount of time in my testing.
  2. The above still requires traversing and waking up every object on the site. Even better would be to make a catalog query to get just the content with local rules for the user. I am not sure if this is currently possible. And although the catalog is there for Plone, I'm not sure if CMFCore can assume such a catalog exists.
@ewohnlich
Copy link
Contributor Author

ewohnlich commented Jun 18, 2024

It is slightly more complicated than I first understood. There is actually only one reindex call (and it's for the portal root), because the recursive calls to itself set reindex=0. However, reindexing on the portal root is still a very expensive process since reindexObjectSecurity is itself recursive. We still don't need to do call this in a lot of cases.

I think something like this may work, with my changes noted in comments

      if _checkPermission(ChangeLocalRoles, obj):
           for member_id in member_ids:
               if obj.get_local_roles_for_userid(userid=member_id):
                   obj.manage_delLocalRoles(userids=member_ids)
                   # change - move the reindex under this condition
                   if reindex and hasattr(aq_base(obj), 'reindexObjectSecurity'):
                       # reindexObjectSecurity is always recursive
                       obj.reindexObjectSecurity()
                   break

       if recursive and hasattr(aq_base(obj), 'contentValues'):
           for subobj in obj.contentValues():
               # change - keep reindex value
               self.deleteLocalRoles(subobj, member_ids, reindex, 1)

@ewohnlich ewohnlich reopened this Jun 18, 2024
@d-maurer
Copy link
Contributor

  1. I think the reindex section can be moved into this condition https://github.com/zopefoundation/Products.CMFCore/blob/master/src/Products/CMFCore/MembershipTool.py#L463 so that it only happens if there are actually local roles to delete. This saved a significant amount of time in my testing.

Be very careful! Local roles affect not only the object where they are assigned but also all descendants. This implies that deleting a local role may require reindexObjectSecurity on all descendants. Not doing this can lead to inconsistencies in the the security related indexes (usually allowed_roles_and_users).

In the use case of user deletion, the inconsistency will not have an immediate effect. But if a user should in the future be created with the same id (as the one deleted), then his searches may find objects he cannot access.

For the reason above, I am against calling reindexObjectSecurity only if local roles are assigned at this object.

Should your application require something like this, I suggest to implement your own MemberShipTool which handle local role deletion in a way acceptable for your concrete situation.

@ewohnlich
Copy link
Contributor Author

ewohnlich commented Jun 18, 2024

But shouldn't that be accounted for in my proposal? It would run a reindex on any object that has local roles and all of its descendants. This is due to reindexObjectSecurity always being recursive - if you call only portal.reindexObjectSecurity() it will actually update the security indexes of brain in the catalog.

@d-maurer
Copy link
Contributor

d-maurer commented Jun 18, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants