Add DeclarativePolicy patch to memoize some attributes
What does this MR do and why?
Description taken from gitlab-org/ruby/gems/declarative-policy!52 (closed).
This MR memoizes:
DeclarativePolicy::Base.ability_map
DeclarativePolicy::Base.conditions
DeclarativePolicy::Base.global_actions
DeclarativePolicy::Base.delegations
In #420623 (closed) after adding an ability to filter out notes the Exporter User is not permitted to read customers started reporting that their projects can not longer be exported & sidekiq node runs out of RAM during export. We filter out notes by iterating them with note.readable_by?(user)
. If enough notes are present, it causes memory usage to skyrocket.
This should also benefit notes rendering in the UI (and all other policy checks).
Example for 500 notes:
Before 800 Mb memory allocated:
require 'memory_profiler'
MemoryProfiler.report { Note.last(500).each { |note| note.readable_by?(User.first) } }.pretty_print(detailed_report: true)
Total allocated: 827235195 bytes (4897665 objects)
Total retained: 3871264 bytes (20684 objects)
allocated memory by gem
-----------------------------------
287181225 declarative_policy-1.1.0
145281644 other
133107381 activesupport-7.0.6
109408432 activerecord-7.0.6
allocated memory by location
-----------------------------------
181285568 /Users/georgekoltsov/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/declarative_policy-1.1.0/lib/declarative_policy/base.rb:77
137862000 <internal:marshal>:35
86137016 /Users/georgekoltsov/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/declarative_policy-1.1.0/lib/declarative_policy/base.rb:20
57233743 /Users/georgekoltsov/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/marginalia-1.11.1/lib/marginalia/comment.rb:115
55162000 /Users/georgekoltsov/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-7.0.6/lib/active_support/cache.rb:1013
After 500 Mb memory allocated:
require 'memory_profiler'
MemoryProfiler.report { Note.last(500).each { |note| note.readable_by?(User.first) } }.pretty_print(detailed_report: true)
Total allocated: 540877937 bytes (4600274 objects)
Total retained: 192823 bytes (853 objects)
allocated memory by gem
-----------------------------------
145376235 other
129580961 activesupport-7.0.6
107732135 activerecord-7.0.6
...
allocated memory by location
-----------------------------------
137997693 <internal:marshal>:35
57103318 /Users/georgekoltsov/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/marginalia-1.11.1/lib/marginalia/comment.rb:115
55217160 /Users/georgekoltsov/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-7.0.6/lib/active_support/cache.rb:1013
46574912 /Users/georgekoltsov/.asdf/installs/ruby/3.1.4/lib/ruby/gems/3.1.0/gems/activesupport-7.0.6/lib/active_support/core_ext/enumerable.rb:78
A rough 37% reduction in memory allocation.
How to set up and validate locally
In Rails console:
ProjectPolicy.conditions.object_id
ProjectPolicy.conditions.object_id
ProjectPolicy.ability_map.object_id
ProjectPolicy.ability_map.object_id
...
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
-
I have evaluated the MR acceptance checklist for this MR.