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

Use MiqPreloader/Relationship improvements in MiqRequestWorkflow #17461

Conversation

NickLaMuro
Copy link
Member

@NickLaMuro NickLaMuro commented May 21, 2018

Extracted from #17354

Built off of and depends on #17457 and #17460

This takes the MiqPreloader.polymorphic_preload_for_child_classes changes, and makes use of them through the fulltree_arranged method to drastically reduce the number of N+1 queries in MiqRequestWorkflow#ems_metadata_tree.

Benchmarks

tl; dr Same as in the other PRs, just different code

Note: There is actually a slight improvement in number of queries called when combining both the changes from this branch, and the previous ones in #17354. This is due to the addition of Host => hosts_scope option which addresses a slightly smaller N+1 for hosts that happen to show up directly in the ems_metadata_tree versus are accessed through the EmsCluster records. In my dataset, this was only 4 hosts in total this affected, but in different scendarios, this might have a bigger affect.

Also, these benchmarks don't integrate the merged changes from #17354 as I have been benchmarking all of these changes from an individual perspective off of a specific commit from master, and wanted to keep the before and after benchmark results consistent with the rest of the related PRs.

The benchmark script used here basically runs the following:

ManageIQ::Providers::Vmware::InfraManager::ProvisionWorkflow.new.init_from_dialog

And is targeting a fairly large EMS, with about 600 hosts.

ms queries query (ms) rows
before 15023 1961 873.4 48395
after 12772 1308 451.2 48395
Before                                                     After
------                                                     -----

Total allocated: 2069091751 bytes (23226536 objects)   |   Total allocated: 2023972840 bytes (22605560 objects)
                                                       |   
allocated objects by gem                               |   allocated objects by gem
-----------------------------------                    |   -----------------------------------
   9665227  pending                                    |      9665227  pending
   5561668  manageiq/app  <<<<<<<<<<                   |      5559167  manageiq/app  <<<<<<<<<<
   3513258  manageiq/lib  <<<<<<<<<<                   |      3508927  manageiq/lib  <<<<<<<<<<
   2512007  activerecord-5.0.7  <<<<<<<<<<             |      2131310  activerecord-5.0.7  <<<<<<<<<<
    861270  activesupport-5.0.7 <<<<<<<<<<             |       839043  activesupport-5.0.7  <<<<<<<<<<
    418737  ancestry-2.2.2                             |       418737  ancestry-2.2.2
    278793  activemodel-5.0.7  <<<<<<<<<<              |       276326  activemodel-5.0.7  <<<<<<<<<<
    178419  ruby-2.3.3/lib  <<<<<<<<<<                 |        77456  ruby-2.3.3/lib  <<<<<<<<<<
    165577  arel-7.1.4  <<<<<<<<<<                     |        59093  arel-7.1.4  <<<<<<<<<<
     52875  manageiq-providers-vmware-0be2f13a0dc9     |        52875  manageiq-providers-vmware-0be2f13a0dc9
     14424  fast_gettext-1.2.0                         |        14424  fast_gettext-1.2.0
      4115  other  <<<<<<<<<<                          |         2809  other  <<<<<<<<<<
        75  default_value_for-3.0.5                    |           75  default_value_for-3.0.5
        68  concurrent-ruby-1.0.5                      |           68  concurrent-ruby-1.0.5
        16  memoist-0.15.0                             |           16  memoist-0.15.0
         4  rubygems                                   |            4  rubygems

Note: The benchmarks for this change do NOT include the changes from other PRs in the links below. Benchmarks of all changes can be found here.

Links

This is a specialized preloader for classes with polymorphic
relationships that allows for targeted preloading for those specific
class types on said polymorphic relationships.  This allows for taking
advantage of those associations by allowing scopes to be applied to the
specific relationships and subsequent calls to the relationship can have
those query definitions applied.
@NickLaMuro
Copy link
Member Author

@miq-bot add_label performance

@syncrou This is the follow-up PR which re-integrates the MiqPreloader work into the MiqRequestWorkflow. Didn't assign anyone because I wasn't sure who it should go to at this point, but at least keeping you in the loop since you did the initial review on #17354

cc @kbrock @Fryguy

This makes a new rspec shared_context that can be used to replicate the
tree building functionality in the specs that test the method
`MiqPreloader.polymorphic_preload_for_child_classes`.  The same data can
then be used in higher level abstraction tests to confirm the
functionality works as expected there as well.
Makes use of MiqPreloader.polymorphic_preload_for_child_classes in
RelationshipMixin.fulltree_arranged to allow the caller to preload
specific resource relationships and sub relationships.
Implements the MiqPreloader.polymorphic_preload_for_child_classes
improvements into the MiqRequestWorkflow#ems_metadata_tree method.  This
significantly cuts down the number of N+1's when accessing the
v_total_vms method from Hosts via EmsClusters.

Also includes the `:v_total_vms` select to the individual hosts in the
ems_metadata_tree incase that method is accessed from those records as
well.
@NickLaMuro NickLaMuro force-pushed the miq_preloader_relationship_mixin_improvements_in_miq_request_workflow branch from ee30828 to aaf21ce Compare May 22, 2018 00:07
@miq-bot
Copy link
Member

miq-bot commented May 22, 2018

Checked commits NickLaMuro/manageiq@2f971d5~...aaf21ce with ruby 2.3.3, rubocop 0.52.1, haml-lint 0.20.0, and yamllint 1.10.0
7 files checked, 4 offenses detected

lib/miq_preloader.rb

@@ -515,7 +515,8 @@ def fulltree_ids_arranged(*args)

# Returns the records in the tree from the root arranged in a tree
def fulltree_arranged(*args)
Relationship.arranged_rels_to_resources(fulltree_rels_arranged(*args))
class_specific_preloaders = args.last.delete(:class_specific_preloaders) if args.last.kind_of?(Hash)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was aware of this, but I was avoiding it since down the chain it is also called in fulltree_rels_arranged. Instead of changing pulling out the options here, I was being explicit and only removing the single key I needed here. Seemed less risky to not mutate args here when it was already being done later in fulltree_rels_arranged.

That said, I am not terribly partial to this line of thought here. I guess the diff for doing this would then look like this:

   def fulltree_arranged(*args)
-    Relationship.arranged_rels_to_resources(fulltree_rels_arranged(*args))
+    options = args.extract_options!
+    class_specific_preloaders = options.delete(:class_specific_preloaders)
+    Relationship.arranged_rels_to_resources(fulltree_rels_arranged(*args, options), true, class_specific_preloaders)
   end

Does make that last line a bit longer, and I am all about shorter lines when possible, but should be the same.

@miq-bot miq-bot closed this Dec 3, 2018
@miq-bot
Copy link
Member

miq-bot commented Dec 3, 2018

This pull request has been automatically closed because it has not been updated for at least 6 months.

Feel free to reopen this pull request if these changes are still valid.

Thank you for all your contributions!

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

Successfully merging this pull request may close these issues.

3 participants