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

Load Lans effeciently in MiqProvisionVirtWorkflow #17381

Conversation

NickLaMuro
Copy link
Member

@NickLaMuro NickLaMuro commented May 3, 2018

Instead of preloading Lan records, splitting them up based on if they are shareable and instantiating entire ActiveRecord instances to only use the name column in a hash, use a specific query to gather and filter those values and generate a hash from that.

IMPORTANT NOTE: The provider PRs linked below should be merged first:

UPDATE: These PRs have been merged, so this is good to be merged now.

As the performance impact from removing the MiqPreloader.preload in this PR will then not be an issue.

Benchmarks

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 715.2 48395
after 8395 1960 758.3 22105
Before                                                               After
------                                                               -----

Total allocated: 2069091751 bytes (23226536 objects)             |   Total allocated: 925043206 bytes (18683089 objects)
                                                                 |   
allocated objects by gem                                         |   allocated objects by gem
-----------------------------------                              |   -----------------------------------
   9665227  pending                                              |      9665227  pending
   5561668  manageiq/app  <<<<<<<<<<                             |      5509120  manageiq/app  <<<<<<<<<<
   3513258  manageiq/lib                                         |      1697100  activerecord-5.0.7  <<<<<<<<<<
   2512007  activerecord-5.0.7  <<<<<<<<<<                       |       834238  activesupport-5.0.7
    861270  activesupport-5.0.7                                  |       418737  ancestry-2.2.2
    418737  ancestry-2.2.2                                       |       188479  activemodel-5.0.7
    278793  activemodel-5.0.7                                    |       178212  ruby-2.3.3/lib
    178419  ruby-2.3.3/lib                                       |       166857  arel-7.1.4
    165577  arel-7.1.4                                           |        13032  fast_gettext-1.2.0
     52875  manageiq-providers-vmware-0be2f13a0dc9  <<<<<<<<<<   |         7789  manageiq/lib
     14424  fast_gettext-1.2.0                                   |         4109  other
      4115  other                                                |           75  default_value_for-3.0.5
        75  default_value_for-3.0.5                              |           60  concurrent-ruby-1.0.5
        68  concurrent-ruby-1.0.5                                |           34  manageiq-providers-vmware-0be2f13a0dc9  <<<<<<<<<<
       ...                                                       |          ...

Note: The benchmarks for this change do NOT include the changes from other PRs (#17354 for example). Benchmarks of all changes can be found here.

Links

Instead of preloading Lan records, splitting them up based on if they are
shareable and instantiating entire ActiveRecord to only use the name
column in a hash, use a specific query to gather and filter those values
and generate a hash from that.
@miq-bot
Copy link
Member

miq-bot commented May 3, 2018

Checked commit NickLaMuro@3dcee40 with ruby 2.3.3, rubocop 0.52.1, haml-lint 0.20.0, and yamllint 1.10.0
2 files checked, 0 offenses detected
Everything looks fine. 🍪

@lan11 = FactoryGirl.create(:lan, :name => "lan_A", :switch_id => s11.id)
@lan12 = FactoryGirl.create(:lan, :name => "lan_B", :switch_id => s12.id)
@lan13 = FactoryGirl.create(:lan, :name => "lan_C", :switch_id => s13.id)
@lan14 = FactoryGirl.create(:lan, :name => "lan_D", :switch_id => s14.id)
Copy link
Contributor

Choose a reason for hiding this comment

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

@NickLaMuro - Were the @lan14 and @other_vm additions to shore up the spec test cases or for another reason?

Copy link
Member Author

Choose a reason for hiding this comment

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

@syncrou Took me a bit to remember why I did it myself!

I was actually to make sure that this test:

expect { workflow.load_hosts_vlans(hosts, {}) }.not_to exceed_query_limit(1)

Was actually being exercised properly when multiple hosts were present. If I left the data as it was, I would have technically passed that spec without actually avoiding an N+1 because we were only testing against 1 host (note, the previous code did a hosts.each. Just wanted to make sure there wasn't a hidden N+1 in there by testing against multiple hosts.

@@ -230,8 +230,6 @@ def available_vlans_and_hosts(options = {})
hosts = get_selected_hosts(src)
unless @vlan_options[:vlans] == false
rails_logger('allowed_vlans', 0)
# TODO: Use Active Record to preload this data?
MiqPreloader.preload(hosts, :lans => :switches)
Copy link
Contributor

Choose a reason for hiding this comment

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

@NickLaMuro - Is pulling this out a dependency on #17354?

Copy link
Member Author

Choose a reason for hiding this comment

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

Nope, don't think so, though maybe I am not understanding the question.

That was how hosts, lans, and switches were being loaded previously, and how "zero SQL queries" were being made in the test previously. This was just using the MiqPreloader.preload code that already existed, and I was just removing it since it was no longer needed.

Did that answer the question?

Copy link
Member Author

Choose a reason for hiding this comment

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

Basically, in the previous versions of the code, this prevented N+1's in the load_hosts_vlans method. This is no longer needed, and avoids a lot of unneeded object allocations.

Copy link
Contributor

@syncrou syncrou left a comment

Choose a reason for hiding this comment

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

@NickLaMuro - This looks good to me.

Copy link
Contributor

@d-m-u d-m-u left a comment

Choose a reason for hiding this comment

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

lgtm

@gmcculloug gmcculloug added this to the Sprint 87 Ending Jun 4, 2018 milestone May 22, 2018
@gmcculloug gmcculloug self-assigned this May 22, 2018
@gmcculloug gmcculloug merged commit d4f111c into ManageIQ:master May 22, 2018
@NickLaMuro
Copy link
Member Author

@miq-bot add_label fine/yes, gaprindashvili/yes

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.

5 participants