-
Notifications
You must be signed in to change notification settings - Fork 26
Optimize entitlement calculation hot paths #77
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,20 +49,13 @@ def initialize(filter:, config: {}) | |
| # member - Entitlements::Models::Person object | ||
| # | ||
| # Returns true if a member of the filter conditions, false otherwise. | ||
| Contract Entitlements::Models::Person => C::Bool | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, so here's the thing. This is in the MIDDLE of the hot path and the allocation for Contracts is really expensive. This method is entirely private and isn't called outside of our code. I think that this contract hurts us more than it helps. |
||
| def member_of_filter?(member) | ||
| # First handle all username entries, regardless of order, because we do not | ||
| # have to mess around with reading groups for those. | ||
| filter.reject { |filter_val| filter_val =~ /\// }.each do |filter_val| | ||
| return true if filter_val.downcase == member.uid.downcase | ||
| end | ||
| return true if filter_usernames.include?(member.uid.downcase) | ||
|
|
||
| # Now handle all group entries. | ||
| filter.select { |filter_val| filter_val =~ /\// }.each do |filter_val| | ||
| filter_groups.each do |filter_val| | ||
| return true if member_of_named_group?(member, filter_val) | ||
| end | ||
|
|
||
| # If we get here there was no match. | ||
| false | ||
| end | ||
|
|
||
|
|
@@ -73,18 +66,27 @@ def member_of_filter?(member) | |
| # group_ref - Optionally a string with a reference to a group to look up | ||
| # | ||
| # Returns true if a member of the group, false otherwise. | ||
| Contract Entitlements::Models::Person, String => C::Bool | ||
| def member_of_named_group?(member, group_ref) | ||
| Entitlements.cache[:member_of_named_group] ||= {} | ||
| Entitlements.cache[:member_of_named_group][group_ref] ||= begin | ||
| member_set = Entitlements::Data::Groups::Calculated::Rules::Group.matches( | ||
| value: group_ref, | ||
| ) | ||
| member_set.map { |person| person.uid.downcase } | ||
| member_set.each_with_object(Set.new) { |person, result| result.add(person.uid.downcase) } | ||
| end | ||
|
|
||
| Entitlements.cache[:member_of_named_group][group_ref].include?(member.uid.downcase) | ||
| end | ||
|
|
||
| def filter_usernames | ||
| @filter_usernames ||= filter.each_with_object(Set.new) do |filter_val, result| | ||
| result.add(filter_val.downcase) unless filter_val.include?("/") | ||
| end | ||
| end | ||
|
|
||
| def filter_groups | ||
| @filter_groups ||= filter.select { |filter_val| filter_val.include?("/") } | ||
| end | ||
|
Comment on lines
+81
to
+89
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Memoizing these values and creating sets out of them should speed up calculations by a decent chunk. |
||
| end | ||
| end | ||
| end | ||
|
|
||
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.
Previously, we had filters that were in some cases being applied two times to the same file. We now have a helper to determine if the filter applies and we only run it once.