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 BinaryBlob to store ManagerRefresh::Target payload #16413

Conversation

agrare
Copy link
Member

@agrare agrare commented Nov 7, 2017

In order to parse pod events for pods which might already be deleted we
need to pass the payload for the pod with the refresh target. This can
however lead to very large queue items as the full payload for a pod can
be quite large.

This moves the payload to a binary blob when the target is created with
a payload, and loads the binary blob then deletes it when the target is
created with a payload_id.

Related: ManageIQ/manageiq-providers-kubernetes#164

@agrare
Copy link
Member Author

agrare commented Nov 7, 2017

cc @Fryguy @Ladas

@agrare agrare requested a review from Ladas November 7, 2017 20:25
@agrare agrare force-pushed the manager_refresh_target_payload_binary_blob branch 3 times, most recently from cf0b1e9 to 164b808 Compare November 7, 2017 21:17
payload_blob = BinaryBlob.find(payload_id)
@options[:payload] = payload_blob.binary
payload_blob.destroy
end
Copy link
Member

Choose a reason for hiding this comment

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

maybe something like this would be clearer?

if options[:payload]
  @options[:payload_id] = BinaryBlob.create!(:binary => options[:payload]).id
elsif options[:payload_id]
  payload_blob = BinaryBlob.find(options[:payload_id])
  @options[:payload] = payload_blob.binary
  payload_blob.destroy
end

Copy link
Member

Choose a reason for hiding this comment

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

I would prefer the actual database access to be moved out of here.

But the if / elsif removes my concern that we are creating the Blob and then deleting it a few instructions later

Copy link
Contributor

Choose a reason for hiding this comment

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

So there is another problem and the reason why I asked about the 'purging'. To maintain the current workflow of: if there is refresh and the process dies, the restarted process will pick up the same refresh again. That means we can't destroy the payload as part of input. We need to refresh first, then delete the payload in post refresh or some scheduled purger looking at orphaned payloads.


payload_id = options[:payload_id]
if payload_id
payload_blob = BinaryBlob.find(payload_id)
Copy link
Member

@kbrock kbrock Nov 7, 2017

Choose a reason for hiding this comment

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

Can we move this to a separate call?

May need to change change k8s InventoryCollectorMixin#parse_target_from_notice
and TargetCollection#add_target

plus there are many uses of Target#load

@agrare agrare force-pushed the manager_refresh_target_payload_binary_blob branch 2 times, most recently from e171d87 to f7b8a9b Compare November 8, 2017 14:49
@kbrock
Copy link
Member

kbrock commented Nov 8, 2017

ok.
How do we clean out the payload?
Is that 100% on the caller now?

@agrare
Copy link
Member Author

agrare commented Nov 8, 2017

@kbrock yes now it is on the caller to call target.payload = nil to clear the binary blob

@cben
Copy link
Contributor

cben commented Nov 8, 2017 via email

@agrare
Copy link
Member Author

agrare commented Nov 8, 2017

Is there any purging on BinaryBlob table, in case we leak them?

Not that I'm aware of we'll have to add it

@Ladas
Copy link
Contributor

Ladas commented Nov 8, 2017

@agrare seems like the added specs are failing :-)

@agrare
Copy link
Member Author

agrare commented Nov 8, 2017

@Ladas working on it :)

Copy link
Contributor

@Ladas Ladas left a comment

Choose a reason for hiding this comment

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

Ok, so we will probably need purging, in a case that this fails during post refresh.

But for now, it looks good 👍 (after CI passes)

payload_blob = BinaryBlob.find(payload_id)
@options[:payload] = payload_blob.binary
payload_blob.destroy
end
Copy link
Contributor

Choose a reason for hiding this comment

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

So there is another problem and the reason why I asked about the 'purging'. To maintain the current workflow of: if there is refresh and the process dies, the restarted process will pick up the same refresh again. That means we can't destroy the payload as part of input. We need to refresh first, then delete the payload in post refresh or some scheduled purger looking at orphaned payloads.

@cben
Copy link
Contributor

cben commented Nov 8, 2017 via email

@Ladas
Copy link
Contributor

Ladas commented Nov 8, 2017

@cben @agrare We could wrap MiqQueue item deletion with BinaryBlob deletion into a transaction? Not sure where is the MiqQueue item actually deleted, it must be after post refresh?

@agrare agrare force-pushed the manager_refresh_target_payload_binary_blob branch 2 times, most recently from 4e81f9f to 5fcfb49 Compare November 8, 2017 17:56
@agrare
Copy link
Member Author

agrare commented Nov 8, 2017

Okay tests updated for the new interface

@agrare agrare force-pushed the manager_refresh_target_payload_binary_blob branch from 5fcfb49 to 326371c Compare November 8, 2017 18:04
Copy link
Contributor

@Ladas Ladas left a comment

Choose a reason for hiding this comment

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

Awesome

@agrare
Copy link
Member Author

agrare commented Nov 8, 2017

The queue item is typically destroyed here destroy_potentially_stale_record after it is delivered. We also destroy queue items here and here.

@agrare agrare force-pushed the manager_refresh_target_payload_binary_blob branch 2 times, most recently from 83816cb to 0078066 Compare November 8, 2017 19:27
@Ladas Ladas mentioned this pull request Nov 20, 2017
1 task
@@ -19,6 +19,7 @@
#
class MiqQueue < ApplicationRecord
belongs_to :handler, :polymorphic => true
has_many :binary_blobs, :as => :resource, :dependent => :nullify
Copy link
Member

Choose a reason for hiding this comment

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

The dependent bit is going to add a query to every delete...we may just want to put nothing here.

@Fryguy
Copy link
Member

Fryguy commented Nov 20, 2017

Can we extract purging into a separate PR? I think that one is less controversial.

@agrare agrare force-pushed the manager_refresh_target_payload_binary_blob branch from f0d971c to e8a467c Compare November 22, 2017 13:56
@agrare
Copy link
Member Author

agrare commented Nov 22, 2017

Can we extract purging into a separate PR? I think that one is less controversial.

Yes, #16524

Copy link
Contributor

@Ladas Ladas left a comment

Choose a reason for hiding this comment

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

Looks great now

@agrare
Copy link
Member Author

agrare commented Dec 13, 2017

Seems to be a weird github bug, can't reply to the comment directly

The dependent bit is going to add a query to every delete...we may just want to put nothing here.

@Fryguy We would have to change the purging scope which currently looks for where(:resource => nil) any ideas?

The best I can come up with is BinaryBlob.where(:resource_type => 'MiqQueue').where.not('resource_id in (select id from miq_queue)') which is a little gross :/

@agrare agrare force-pushed the manager_refresh_target_payload_binary_blob branch from e8a467c to 6449ac2 Compare December 20, 2017 14:04
@@ -13,7 +13,7 @@ def purge_window_size
end

def purge_scope(_older_than = nil)
where(:resource => nil)
where(:resource_type => 'MiqQueue').where.not('resource_id in (select id from miq_queue)')
Copy link
Contributor

Choose a reason for hiding this comment

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

hm, this would explode, given select id from miq_queue would unpack the whole miq queue (that can go to milions)

refresh_queue_items = MiqQueue.where(:method_name => 'refresh') # rails is smart enough to add .select(:id)
where(:resource_type => 'MiqQueue').where.not(:resource_id => refresh_queue_items)

I think :method_name => 'refresh' might be enough to fetch existing refresh MiqQueue items, or maybe more from https://github.com/Ladas/manageiq/blob/acf2ad8e29b9e70858fc99e22614d2112312066c/app/models/ems_refresh.rb#L162 ?

Is purging Zone agnostic? Or we should limit it by zone, if each zone has its own purger?

Copy link
Contributor

Choose a reason for hiding this comment

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

query looks fast enough in hundred k world

2.4.2 :019 > BinaryBlob.where(:resource_type => 'MiqQueue').where.not(:resource_id => refresh_queue_items).count
   (92.6ms)  SELECT COUNT(*) FROM "binary_blobs" WHERE "binary_blobs"."resource_type" = $1 AND ("binary_blobs"."resource_id" NOT IN (SELECT "miq_queue"."id" FROM "miq_queue" WHERE "miq_queue"."method_name" = $2))  [["resource_type", "MiqQueue"], ["method_name", "refresh"]]
  Query Trace > lib/extensions/ar_virtual.rb:741:in `calculate'
 => 351020

Copy link
Member

Choose a reason for hiding this comment

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

Do we only care about purging blobs related to MiqQueue? If not, you can use the polymorphic orphan purging I added in #16754

It uses a join so it should be a bit more efficient than the subquery you have here. Also it won't pull back the ids to the server at all.

Copy link
Member Author

Choose a reason for hiding this comment

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

@carbonin 👍 looks much better, I'll switch to that when yours is merged

@agrare agrare force-pushed the manager_refresh_target_payload_binary_blob branch from 6449ac2 to 0855779 Compare January 18, 2018 19:05
@kbrock
Copy link
Member

kbrock commented Feb 26, 2018

in a perfect world, knowing a blob is used would be hidden - so when we use a different queuing mechanism, it can be used without too much of a change.

Having said that, this change should be a good performance improvement.
can we ship it?

@agrare agrare force-pushed the manager_refresh_target_payload_binary_blob branch from 0855779 to 006e4b0 Compare February 28, 2018 19:38
@agrare
Copy link
Member Author

agrare commented Feb 28, 2018

@Fryguy what do you think about this? This will get the ManagerRefresh::Target objects out of the queue args for amazon/openstack and help us do the watcher for kubernetes

@miq-bot
Copy link
Member

miq-bot commented Mar 16, 2018

This pull request is not mergeable. Please rebase and repush.

@agrare agrare force-pushed the manager_refresh_target_payload_binary_blob branch from 006e4b0 to 41f3e1d Compare March 16, 2018 19:15
@miq-bot
Copy link
Member

miq-bot commented Mar 16, 2018

Checked commits agrare/manageiq@fe72473~...41f3e1d with ruby 2.3.3, rubocop 0.52.1, haml-lint 0.20.0, and yamllint 1.10.0
6 files checked, 10 offenses detected

app/models/ems_refresh.rb

app/models/miq_queue.rb

spec/models/manager_refresh/target_spec.rb

@gtanzillo
Copy link
Member

@Fryguy Ok to merge this?

@agrare agrare closed this Jul 1, 2018
@agrare agrare deleted the manager_refresh_target_payload_binary_blob branch July 16, 2018 17:04
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.

10 participants