Improve account index migration (#7684)

* Improve account index migration

- Display more progress in stdout
- Catch PG::UniqueViolation when re-attributing favourites
- Skip callbacks and validations when re-attributing other relationships

* Use in_batches to reduce table lock-up during account merge

* Use #say_with_time to benchmark each deduplication
This commit is contained in:
Eugen Rochko 2018-05-31 17:09:09 +02:00 committed by GitHub
parent 1e938b966e
commit 19b4c666f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -39,6 +39,7 @@ class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2]
accounts = accounts.first.local? ? accounts.sort_by(&:created_at) : accounts.sort_by(&:updated_at).reverse accounts = accounts.first.local? ? accounts.sort_by(&:created_at) : accounts.sort_by(&:updated_at).reverse
reference_account = accounts.shift reference_account = accounts.shift
say_with_time "Deduplicating @#{reference_account.acct} (#{accounts.size} duplicates)..." do
accounts.each do |other_account| accounts.each do |other_account|
if other_account.public_key == reference_account.public_key if other_account.public_key == reference_account.public_key
# The accounts definitely point to the same resource, so # The accounts definitely point to the same resource, so
@ -55,10 +56,11 @@ class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2]
other_account.destroy other_account.destroy
end end
end end
end
def merge_accounts!(main_account, duplicate_account) def merge_accounts!(main_account, duplicate_account)
[Status, Favourite, Mention, StatusPin, StreamEntry].each do |klass| [Status, Mention, StatusPin, StreamEntry].each do |klass|
klass.where(account_id: duplicate_account.id).update_all(account_id: main_account.id) klass.where(account_id: duplicate_account.id).in_batches.update_all(account_id: main_account.id)
end end
# Since it's the same remote resource, the remote resource likely # Since it's the same remote resource, the remote resource likely
@ -67,19 +69,19 @@ class FixAccountsUniqueIndex < ActiveRecord::Migration[5.2]
# of the index bug users could have *also* followed the reference # of the index bug users could have *also* followed the reference
# account already, therefore mass update will not work and we need # account already, therefore mass update will not work and we need
# to check for (and skip past) uniqueness errors # to check for (and skip past) uniqueness errors
[Follow, FollowRequest, Block, Mute].each do |klass| [Favourite, Follow, FollowRequest, Block, Mute].each do |klass|
klass.where(account_id: duplicate_account.id).find_each do |record| klass.where(account_id: duplicate_account.id).find_each do |record|
begin begin
record.update(account_id: main_account.id) record.update_attribute(:account_id, main_account.id)
rescue ActiveRecord::RecordNotUnique rescue PG::UniqueViolation
next next
end end
end end
klass.where(target_account_id: duplicate_account.id).find_each do |record| klass.where(target_account_id: duplicate_account.id).find_each do |record|
begin begin
record.update(target_account_id: main_account.id) record.update_attribute(:target_account_id, main_account.id)
rescue ActiveRecord::RecordNotUnique rescue PG::UniqueViolation
next next
end end
end end