From bfcdacacf19f8fca2726b2fa0a0f346752abd064 Mon Sep 17 00:00:00 2001 From: Ladislav Smola Date: Wed, 19 Jul 2017 13:23:57 +0200 Subject: [PATCH 1/7] Allow IC to store what was created/updated/deleted Allow IC to store what was created/updated/deleted --- .../manager_refresh/inventory_collection.rb | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/app/models/manager_refresh/inventory_collection.rb b/app/models/manager_refresh/inventory_collection.rb index c3bc7a0415a..8575147c2bc 100644 --- a/app/models/manager_refresh/inventory_collection.rb +++ b/app/models/manager_refresh/inventory_collection.rb @@ -9,7 +9,7 @@ class InventoryCollection :custom_db_finder, :check_changed, :arel, :builder_params, :loaded_references, :db_data_index, :inventory_object_attributes, :name, :saver_strategy, :parent_inventory_collections, :manager_uuids, :skeletal_manager_uuids, :targeted_arel, :targeted, :manager_ref_allowed_nil, :use_ar_object, - :secondary_refs, :secondary_indexes + :secondary_refs, :secondary_indexes, :created_records, :updated_records, :deleted_records delegate :each, :size, :to => :to_a @@ -394,12 +394,28 @@ def initialize(model_class: nil, manager_ref: nil, association: nil, parent: nil @db_data_index = nil @data_collection_finalized = false + @created_records = [] + @updated_records = [] + @deleted_records = [] + blacklist_attributes!(attributes_blacklist) if attributes_blacklist.present? whitelist_attributes!(attributes_whitelist) if attributes_whitelist.present? validate_inventory_collection! end + def store_created_records(records) + @created_records += records_identities(records) + end + + def store_updated_records(records) + @updated_records += records_identities(records) + end + + def store_deleted_records(records) + @deleted_records += records_identities(records) + end + def to_a data end @@ -947,6 +963,19 @@ def full_collection_for_comparison attr_writer :attributes_blacklist, :attributes_whitelist, :db_data_index, :parent_inventory_collections + # Returns array of records identities + def records_identities(records) + records = [records] unless records.kind_of?(Array) + records.map { |record| record_identity(record) } + end + + # Returns a hash with a simple record identity + def record_identity(record) + { + :id => record.try(:[], :id) || record.try(:id) + } + end + # Finds manager_uuid in the DB. Using a configured strategy we cache obtained data in the db_data_index, so the # same find will not hit database twice. Also if we use lazy_links and this is called when # data_collection_finalized?, we load all data from the DB, referenced by lazy_links, in one query. From 4bc5a944e4277d8cdfb69cb02826be127f7ccb1d Mon Sep 17 00:00:00 2001 From: Ladislav Smola Date: Wed, 19 Jul 2017 13:31:12 +0200 Subject: [PATCH 2/7] Unify default and concurrent_safe savers and store counts Unify default and concurrent_safe savers and store counts of what was created/updated/deleted. --- .../save_collection/saver/base.rb | 59 ++++++++++++- .../save_collection/saver/concurrent_safe.rb | 53 +----------- .../save_collection/saver/default.rb | 86 +++++-------------- 3 files changed, 79 insertions(+), 119 deletions(-) diff --git a/app/models/manager_refresh/save_collection/saver/base.rb b/app/models/manager_refresh/save_collection/saver/base.rb index 488100d43ad..c890538e399 100644 --- a/app/models/manager_refresh/save_collection/saver/base.rb +++ b/app/models/manager_refresh/save_collection/saver/base.rb @@ -12,6 +12,7 @@ def initialize(inventory_collection) # Private attrs @unique_index_keys = inventory_collection.manager_ref_to_cols @unique_db_primary_keys = Set.new + @unique_db_indexes = Set.new end def save_inventory_collection! @@ -30,7 +31,57 @@ def save_inventory_collection! private - attr_reader :unique_index_keys, :unique_db_primary_keys + attr_reader :unique_index_keys, :unique_db_primary_keys, :unique_db_indexes + + def save!(inventory_collection, association) + attributes_index = {} + inventory_objects_index = {} + inventory_collection.each do |inventory_object| + attributes = inventory_object.attributes(inventory_collection) + index = inventory_object.manager_uuid + + attributes_index[index] = attributes + inventory_objects_index[index] = inventory_object + end + + _log.info("*************** PROCESSING #{inventory_collection} of size #{inventory_collection.size} *************") + # Records that are in the DB, we will be updating or deleting them. + ActiveRecord::Base.transaction do + association.find_each do |record| + index = inventory_collection.object_index_with_keys(unique_index_keys, record) + + next unless assert_distinct_relation(record) + next unless assert_unique_record(record, index) + + inventory_object = inventory_objects_index.delete(index) + hash = attributes_index.delete(index) + + if inventory_object.nil? + # Record was found in the DB but not sent for saving, that means it doesn't exist anymore and we should + # delete it from the DB. + delete_record!(inventory_collection, record) if inventory_collection.delete_allowed? + else + # Record was found in the DB and sent for saving, we will be updating the DB. + update_record!(inventory_collection, record, hash, inventory_object) if assert_referential_integrity(hash, inventory_object) + end + end + end + + # Records that were not found in the DB but sent for saving, we will be creating these in the DB. + if inventory_collection.create_allowed? + ActiveRecord::Base.transaction do + inventory_objects_index.each do |index, inventory_object| + hash = attributes_index.delete(index) + + create_record!(inventory_collection, hash, inventory_object) if assert_referential_integrity(hash, inventory_object) + end + end + end + _log.info("*************** PROCESSED #{inventory_collection}, "\ + "created=#{inventory_collection.created_records.count}, "\ + "updated=#{inventory_collection.updated_records.count}, "\ + "deleted=#{inventory_collection.deleted_records.count} *************") + end def batch_size inventory_collection.batch_size @@ -61,8 +112,12 @@ def delete_complement(inventory_collection) end def delete_record!(inventory_collection, record) - return false unless inventory_collection.delete_allowed? record.public_send(inventory_collection.delete_method) + inventory_collection.store_deleted_records(record) + end + + def assert_unique_record(_record, _index) + # TODO(lsmola) can go away once we indexed our DB with unique indexes true end diff --git a/app/models/manager_refresh/save_collection/saver/concurrent_safe.rb b/app/models/manager_refresh/save_collection/saver/concurrent_safe.rb index ab79cce8549..23e9e24b599 100644 --- a/app/models/manager_refresh/save_collection/saver/concurrent_safe.rb +++ b/app/models/manager_refresh/save_collection/saver/concurrent_safe.rb @@ -3,55 +3,6 @@ module Saver class ConcurrentSafe < ManagerRefresh::SaveCollection::Saver::Base private - def save!(inventory_collection, association) - attributes_index = {} - inventory_objects_index = {} - inventory_collection.each do |inventory_object| - attributes = inventory_object.attributes(inventory_collection) - index = inventory_object.manager_uuid - - attributes_index[index] = attributes - inventory_objects_index[index] = inventory_object - end - - inventory_collection_size = inventory_collection.size - deleted_counter = 0 - created_counter = 0 - _log.info("*************** PROCESSING #{inventory_collection} of size #{inventory_collection_size} *************") - # Records that are in the DB, we will be updating or deleting them. - ActiveRecord::Base.transaction do - association.find_each do |record| - next unless assert_distinct_relation(record) - - index = inventory_collection.object_index_with_keys(unique_index_keys, record) - - inventory_object = inventory_objects_index.delete(index) - hash = attributes_index.delete(index) - - if inventory_object.nil? - # Record was found in the DB but not sent for saving, that means it doesn't exist anymore and we should - # delete it from the DB. - deleted_counter += 1 if delete_record!(inventory_collection, record) - else - # Record was found in the DB and sent for saving, we will be updating the DB. - update_record!(inventory_collection, record, hash, inventory_object) - end - end - end - - # Records that were not found in the DB but sent for saving, we will be creating these in the DB. - if inventory_collection.create_allowed? - ActiveRecord::Base.transaction do - inventory_objects_index.each do |index, inventory_object| - create_record!(inventory_collection, attributes_index.delete(index), inventory_object) - created_counter += 1 - end - end - end - _log.info("*************** PROCESSED #{inventory_collection}, created=#{created_counter}, "\ - "updated=#{inventory_collection_size - created_counter}, deleted=#{deleted_counter} *************") - end - def update_record!(inventory_collection, record, hash, inventory_object) assign_attributes_for_update!(hash, inventory_collection, time_now) record.assign_attributes(hash.except(:id, :type)) @@ -64,14 +15,13 @@ def update_record!(inventory_collection, record, hash, inventory_object) end update_query.update_all(hash) + inventory_collection.store_updated_records(record) end inventory_object.id = record.id end def create_record!(inventory_collection, hash, inventory_object) - return unless assert_referential_integrity(hash, inventory_object) - all_attribute_keys = hash.keys hash = inventory_collection.model_class.new(hash).attributes.symbolize_keys assign_attributes_for_create!(hash, inventory_collection, time_now) @@ -80,6 +30,7 @@ def create_record!(inventory_collection, hash, inventory_object) build_insert_query(inventory_collection, all_attribute_keys, [hash]) ) inventory_object.id = result_id + inventory_collection.store_created_records(inventory_object) end end end diff --git a/app/models/manager_refresh/save_collection/saver/default.rb b/app/models/manager_refresh/save_collection/saver/default.rb index 881010054a7..686c7991aa6 100644 --- a/app/models/manager_refresh/save_collection/saver/default.rb +++ b/app/models/manager_refresh/save_collection/saver/default.rb @@ -3,83 +3,37 @@ module Saver class Default < ManagerRefresh::SaveCollection::Saver::Base private - def save!(inventory_collection, association) - attributes_index = {} - inventory_objects_index = {} - inventory_collection.each do |inventory_object| - attributes = inventory_object.attributes(inventory_collection) - index = inventory_object.manager_uuid - - attributes_index[index] = attributes - inventory_objects_index[index] = inventory_object - end - - unique_db_indexes = Set.new - - inventory_collection_size = inventory_collection.size - deleted_counter = 0 - created_counter = 0 - _log.info("*************** PROCESSING #{inventory_collection} of size #{inventory_collection_size} *************") - # Records that are in the DB, we will be updating or deleting them. - ActiveRecord::Base.transaction do - association.find_each do |record| - next unless assert_distinct_relation(record) - - index = inventory_collection.object_index_with_keys(unique_index_keys, record) - - # TODO(lsmola) can go away once we indexed our DB with unique indexes - if unique_db_indexes.include?(index) # Include on Set is O(1) - # We have a duplicate in the DB, destroy it. A find_each method does automatically .order(:id => :asc) - # so we always keep the oldest record in the case of duplicates. - _log.warn("A duplicate record was detected and destroyed, inventory_collection: "\ - "'#{inventory_collection}', record: '#{record}', duplicate_index: '#{index}'") - record.destroy - else - unique_db_indexes << index - end - - inventory_object = inventory_objects_index.delete(index) - hash = attributes_index.delete(index) - - if inventory_object.nil? - # Record was found in the DB but not sent for saving, that means it doesn't exist anymore and we should - # delete it from the DB. - deleted_counter += 1 if delete_record!(inventory_collection, record) - else - # Record was found in the DB and sent for saving, we will be updating the DB. - update_record!(inventory_collection, record, hash, inventory_object) - end - end - end - - # Records that were not found in the DB but sent for saving, we will be creating these in the DB. - if inventory_collection.create_allowed? - ActiveRecord::Base.transaction do - inventory_objects_index.each do |index, inventory_object| - hash = attributes_index.delete(index) - create_record!(inventory_collection, hash, inventory_object) - created_counter += 1 - end - end - end - _log.info("*************** PROCESSED #{inventory_collection}, created=#{created_counter}, "\ - "updated=#{inventory_collection_size - created_counter}, deleted=#{deleted_counter} *************") - end - def update_record!(inventory_collection, record, hash, inventory_object) record.assign_attributes(hash.except(:id, :type)) - record.save if !inventory_collection.check_changed? || record.changed? + if !inventory_collection.check_changed? || record.changed? + record.save + inventory_collection.store_updated_records(record) + end inventory_object.id = record.id end def create_record!(inventory_collection, hash, inventory_object) - return unless assert_referential_integrity(hash, inventory_object) - record = inventory_collection.model_class.create!(hash.except(:id)) + inventory_collection.store_created_records(record) inventory_object.id = record.id end + + def assert_unique_record(record, index) + # TODO(lsmola) can go away once we indexed our DB with unique indexes + if unique_db_indexes.include?(index) # Include on Set is O(1) + # We have a duplicate in the DB, destroy it. A find_each method does automatically .order(:id => :asc) + # so we always keep the oldest record in the case of duplicates. + _log.warn("A duplicate record was detected and destroyed, inventory_collection: "\ + "'#{inventory_collection}', record: '#{record}', duplicate_index: '#{index}'") + record.destroy + return false + else + unique_db_indexes << index + end + true + end end end end From d08f793ea779dcd0a718dd5e1c4cd86e79fdca89 Mon Sep 17 00:00:00 2001 From: Ladislav Smola Date: Wed, 19 Jul 2017 13:32:43 +0200 Subject: [PATCH 3/7] Store counts for concurrent safe batch saver Store counts for concurrent safe batch saver. Counts and ids of what was created/updated/deleted. --- .../saver/concurrent_safe_batch.rb | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/app/models/manager_refresh/save_collection/saver/concurrent_safe_batch.rb b/app/models/manager_refresh/save_collection/saver/concurrent_safe_batch.rb index a27ea64ee96..b59043c44a0 100644 --- a/app/models/manager_refresh/save_collection/saver/concurrent_safe_batch.rb +++ b/app/models/manager_refresh/save_collection/saver/concurrent_safe_batch.rb @@ -21,11 +21,7 @@ def save!(inventory_collection, association) all_attribute_keys += [:created_on, :updated_on] if inventory_collection.supports_timestamps_on_variant? all_attribute_keys += [:created_at, :updated_at] if inventory_collection.supports_timestamps_at_variant? - inventory_collection_size = inventory_collection.size - deleted_counter = 0 - created_counter = 0 - updated_counter = 0 - _log.info("*************** PROCESSING #{inventory_collection} of size #{inventory_collection_size} *************") + _log.info("*************** PROCESSING #{inventory_collection} of size #{inventory_collection.size} *************") hashes_for_update = [] records_for_destroy = [] @@ -45,7 +41,6 @@ def save!(inventory_collection, association) # delete it from the DB. if inventory_collection.delete_allowed? records_for_destroy << record - deleted_counter += 1 end else # Record was found in the DB and sent for saving, we will be updating the DB. @@ -69,7 +64,7 @@ def save!(inventory_collection, association) # Update in batches if hashes_for_update.size >= batch_size update_records!(inventory_collection, all_attribute_keys, hashes_for_update) - updated_counter += hashes_for_update.count + inventory_collection.store_updated_records(hashes_for_update) hashes_for_update = [] end @@ -77,13 +72,13 @@ def save!(inventory_collection, association) # Destroy in batches if records_for_destroy.size >= batch_size destroy_records(records_for_destroy) + inventory_collection.store_deleted_records(records_for_destroy) records_for_destroy = [] end end # Update the last batch update_records!(inventory_collection, all_attribute_keys, hashes_for_update) - updated_counter += hashes_for_update.count hashes_for_update = [] # Cleanup so GC can release it sooner # Destroy the last batch @@ -95,11 +90,12 @@ def save!(inventory_collection, association) if inventory_collection.create_allowed? inventory_objects_index.each_slice(batch_size) do |batch| create_records!(inventory_collection, all_attribute_keys, batch, attributes_index) - created_counter += batch.size end end - _log.info("*************** PROCESSED #{inventory_collection}, created=#{created_counter}, "\ - "updated=#{updated_counter}, deleted=#{deleted_counter} *************") + _log.info("*************** PROCESSED #{inventory_collection}, "\ + "created=#{inventory_collection.created_records.count}, "\ + "updated=#{inventory_collection.updated_records.count}, "\ + "deleted=#{inventory_collection.deleted_records.count} *************") end def destroy_records(records) @@ -135,6 +131,7 @@ def create_records!(inventory_collection, all_attribute_keys, batch, attributes_ assign_attributes_for_create!(hash, inventory_collection, create_time) next unless assert_referential_integrity(hash, inventory_object) + inventory_collection.store_created_records(hash) hashes << hash # Index on Unique Columns values, so we can easily fill in the :id later From 71a20a3e32b8ed4f4744fc09556186fadd97db47 Mon Sep 17 00:00:00 2001 From: Ladislav Smola Date: Wed, 19 Jul 2017 13:33:49 +0200 Subject: [PATCH 4/7] Test that we correctly store what was created/updated/deleted in IC Test that we correctly store what was created/updated/deleted in IC --- .../single_inventory_collection_spec.rb | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/spec/models/manager_refresh/save_inventory/single_inventory_collection_spec.rb b/spec/models/manager_refresh/save_inventory/single_inventory_collection_spec.rb index 35aebd0c1a9..632e7bb0d66 100644 --- a/spec/models/manager_refresh/save_inventory/single_inventory_collection_spec.rb +++ b/spec/models/manager_refresh/save_inventory/single_inventory_collection_spec.rb @@ -132,6 +132,11 @@ # Invoke the InventoryCollections saving ManagerRefresh::SaveInventory.save_inventory(@ems, @data.values) + # Check the InventoryCollection result matches what was created/deleted/updated + expect(@data[:vms].created_records).to match_array([]) + expect(@data[:vms].updated_records).to match_array([{:id => @vm1.id}, {:id => @vm2.id}]) + expect(@data[:vms].deleted_records).to match_array([]) + # Assert that saved data have the updated values, checking id to make sure the original records are updated assert_all_records_match_hashes( [Vm.all, @ems.vms], @@ -140,6 +145,28 @@ ) end + it 'updates 1 existing VM' do + # Fill the InventoryCollections with data, that have a modified name + add_data_to_inventory_collection(@data[:vms], + vm_data(1), + vm_data(2).merge(:name => "vm_changed_name_2")) + + # Invoke the InventoryCollections saving + ManagerRefresh::SaveInventory.save_inventory(@ems, @data.values) + + # Check the InventoryCollection result matches what was created/deleted/updated + expect(@data[:vms].created_records).to match_array([]) + expect(@data[:vms].updated_records).to match_array([{:id => @vm2.id}]) + expect(@data[:vms].deleted_records).to match_array([]) + + # Assert that saved data have the updated values, checking id to make sure the original records are updated + assert_all_records_match_hashes( + [Vm.all, @ems.vms], + {:id => @vm1.id, :ems_ref => "vm_ems_ref_1", :name => "vm_name_1", :location => "vm_location_1"}, + {:id => @vm2.id, :ems_ref => "vm_ems_ref_2", :name => "vm_changed_name_2", :location => "vm_location_2"} + ) + end + it 'creates new VMs' do # Fill the InventoryCollections with data, that have a new VM add_data_to_inventory_collection(@data[:vms], @@ -150,6 +177,12 @@ # Invoke the InventoryCollections saving ManagerRefresh::SaveInventory.save_inventory(@ems, @data.values) + # Check the InventoryCollection result matches what was created/deleted/updated + @vm3 = Vm.find_by(:ems_ref => "vm_ems_ref_3") + expect(@data[:vms].created_records).to match_array([{:id => @vm3.id}]) + expect(@data[:vms].updated_records).to match_array([{:id => @vm1.id}, {:id => @vm2.id}]) + expect(@data[:vms].deleted_records).to match_array([]) + # Assert that saved data contain the new VM assert_all_records_match_hashes( [Vm.all, @ems.vms], @@ -167,6 +200,11 @@ # Invoke the InventoryCollections saving ManagerRefresh::SaveInventory.save_inventory(@ems, @data.values) + # Check the InventoryCollection result matches what was created/deleted/updated + expect(@data[:vms].created_records).to match_array([]) + expect(@data[:vms].updated_records).to match_array([{:id => @vm1.id}]) + expect(@data[:vms].deleted_records).to match_array([{:id => @vm2.id}]) + # Assert that saved data do miss the deleted VM assert_all_records_match_hashes( [Vm.all, @ems.vms], @@ -183,6 +221,12 @@ # Invoke the InventoryCollections saving ManagerRefresh::SaveInventory.save_inventory(@ems, @data.values) + # Check the InventoryCollection result matches what was created/deleted/updated + @vm3 = Vm.find_by(:ems_ref => "vm_ems_ref_3") + expect(@data[:vms].created_records).to match_array([{:id => @vm3.id}]) + expect(@data[:vms].updated_records).to match_array([{:id => @vm1.id}]) + expect(@data[:vms].deleted_records).to match_array([{:id => @vm2.id}]) + # Assert that saved data have the new VM and miss the deleted VM assert_all_records_match_hashes( [Vm.all, @ems.vms], From 01cbe8ee867b9dfce2130dd2b4e0861caf729093 Mon Sep 17 00:00:00 2001 From: Ladislav Smola Date: Wed, 19 Jul 2017 13:55:22 +0200 Subject: [PATCH 5/7] Move store_created_records code after records creation Move store_created_records code after records creation --- .../save_collection/saver/concurrent_safe_batch.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/manager_refresh/save_collection/saver/concurrent_safe_batch.rb b/app/models/manager_refresh/save_collection/saver/concurrent_safe_batch.rb index b59043c44a0..3380ec6b500 100644 --- a/app/models/manager_refresh/save_collection/saver/concurrent_safe_batch.rb +++ b/app/models/manager_refresh/save_collection/saver/concurrent_safe_batch.rb @@ -131,7 +131,6 @@ def create_records!(inventory_collection, all_attribute_keys, batch, attributes_ assign_attributes_for_create!(hash, inventory_collection, create_time) next unless assert_referential_integrity(hash, inventory_object) - inventory_collection.store_created_records(hash) hashes << hash # Index on Unique Columns values, so we can easily fill in the :id later @@ -143,6 +142,7 @@ def create_records!(inventory_collection, all_attribute_keys, batch, attributes_ result = ActiveRecord::Base.connection.execute( build_insert_query(inventory_collection, all_attribute_keys, hashes) ) + inventory_collection.store_created_records(result) if inventory_collection.dependees.present? # We need to get primary keys of the created objects, but only if there are dependees that would use them map_ids_to_inventory_objects(inventory_collection, indexed_inventory_objects, all_attribute_keys, hashes, result) From 50116283482ff89f7f65c3a2bbaf69a8049372f9 Mon Sep 17 00:00:00 2001 From: Ladislav Smola Date: Wed, 19 Jul 2017 13:58:26 +0200 Subject: [PATCH 6/7] Enforce that identity of the create/updated/deleted record is present Enforce that identity of the create/updated/deleted record is present --- app/models/manager_refresh/inventory_collection.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/manager_refresh/inventory_collection.rb b/app/models/manager_refresh/inventory_collection.rb index 8575147c2bc..561c9644971 100644 --- a/app/models/manager_refresh/inventory_collection.rb +++ b/app/models/manager_refresh/inventory_collection.rb @@ -971,8 +971,10 @@ def records_identities(records) # Returns a hash with a simple record identity def record_identity(record) + identity = record.try(:[], :id) || record.try(:[], "id") || record.try(:id) + raise "Cannot obtain identity of the #{record}" if identity.blank? { - :id => record.try(:[], :id) || record.try(:id) + :id => identity } end From 42f74aa4c013582216a3c9f22beadf75f867c9c3 Mon Sep 17 00:00:00 2001 From: Ladislav Smola Date: Wed, 19 Jul 2017 14:57:33 +0200 Subject: [PATCH 7/7] Correct storing of deleted and updated records for a batch strategy Correct storing of deleted and updated records for a batch strategy --- .../save_collection/saver/concurrent_safe_batch.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/manager_refresh/save_collection/saver/concurrent_safe_batch.rb b/app/models/manager_refresh/save_collection/saver/concurrent_safe_batch.rb index 3380ec6b500..2809e0003f4 100644 --- a/app/models/manager_refresh/save_collection/saver/concurrent_safe_batch.rb +++ b/app/models/manager_refresh/save_collection/saver/concurrent_safe_batch.rb @@ -56,6 +56,7 @@ def save!(inventory_collection, association) hash.symbolize_keys end assign_attributes_for_update!(hash_for_update, inventory_collection, update_time) + inventory_collection.store_updated_records(record) hashes_for_update << hash_for_update.except(:id, :type) end @@ -64,7 +65,6 @@ def save!(inventory_collection, association) # Update in batches if hashes_for_update.size >= batch_size update_records!(inventory_collection, all_attribute_keys, hashes_for_update) - inventory_collection.store_updated_records(hashes_for_update) hashes_for_update = [] end @@ -83,6 +83,7 @@ def save!(inventory_collection, association) # Destroy the last batch destroy_records(records_for_destroy) + inventory_collection.store_deleted_records(records_for_destroy) records_for_destroy = [] # Cleanup so GC can release it sooner all_attribute_keys << :type if inventory_collection.supports_sti?