Skip to content

Commit

Permalink
write merge data less often
Browse files Browse the repository at this point in the history
refs CORE-2561

test plan
 - specs should pass

Change-Id: I507a1b5a61044e4fee96c49a2857252ae9a755c9
Reviewed-on: https://gerrit.instructure.com/185436
Tested-by: Jenkins
Reviewed-by: James Williams <[email protected]>
QA-Review: James Williams <[email protected]>
Product-Review: Rob Orton <[email protected]>
  • Loading branch information
roor0 committed Mar 15, 2019
1 parent b56e48f commit f84d419
Showing 1 changed file with 31 additions and 22 deletions.
53 changes: 31 additions & 22 deletions lib/user_merge.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ def self.from(user)
end

attr_reader :from_user
attr_accessor :data

def initialize(from_user)
@from_user = from_user
@data = []
end

def into(target_user)
Expand Down Expand Up @@ -149,7 +151,7 @@ def handle_communication_channels(target_user, user_merge_data)
User.clone_communication_channel(cc, target_user, max_position)
new_cc = target_user.communication_channels.where.not(id: known_ccs).take
known_ccs << new_cc.id
user_merge_data.add_more_data([new_cc], user: target_user, workflow_state: 'non_existent')
user_merge_data.build_more_data([new_cc], user: target_user, workflow_state: 'non_existent', data: data)
end

next unless target_cc
Expand All @@ -173,31 +175,33 @@ def finish_ccs(max_position, target_user, to_retire_ids, user_merge_data)
else
from_user.shard.activate do
ccs = CommunicationChannel.where(id: to_retire_ids).where.not(workflow_state: 'retired')
user_merge_data.add_more_data(ccs) unless to_retire_ids.empty?
user_merge_data.build_more_data(ccs, data: data) unless to_retire_ids.empty?
ccs.update_all(workflow_state: 'retired') unless to_retire_ids.empty?
end
scope = from_user.communication_channels.where.not(workflow_state: 'retired')
scope = scope.where.not(id: to_retire_ids) unless to_retire_ids.empty?
unless scope.empty?
user_merge_data.add_more_data(scope)
user_merge_data.build_more_data(scope, data: data)
scope.update_all(["user_id=?, position=position+?", target_user, max_position])
end
end
user_merge_data.bulk_insert_merge_data(data)
@data = []
end

def handle_cross_shard_cc(target_user, user_merge_data)
ccs = from_user.communication_channels.where.not(workflow_state: 'retired')
user_merge_data.add_more_data(ccs) unless ccs.empty?
user_merge_data.build_more_data(ccs, data: data) unless ccs.empty?
ccs.update_all(workflow_state: 'retired') unless ccs.empty?

from_user.user_services.each do |us|
new_us = us.clone
new_us.shard = target_user.shard
new_us.user = target_user
new_us.save!
user_merge_data.add_more_data([new_us], user: target_user, workflow_state: 'non_existent')
user_merge_data.build_more_data([new_us], user: target_user, workflow_state: 'non_existent', data: data)
end
user_merge_data.add_more_data(from_user.user_services)
user_merge_data.build_more_data(from_user.user_services, data: data)
from_user.user_services.delete_all
end

Expand Down Expand Up @@ -240,12 +244,13 @@ def handle_conflicting_ccs(source_cc, target_cc, target_user, max_position)
def move_observees(target_user, user_merge_data)
# record all the records before destroying them
# pass the from_user since user_id will be the observer
user_merge_data.add_more_data(from_user.as_observer_observation_links, user: from_user)
user_merge_data.add_more_data(from_user.as_student_observation_links)
user_merge_data.build_more_data(from_user.as_observer_observation_links, user: from_user, data: data)
user_merge_data.build_more_data(from_user.as_student_observation_links, data: data)
# delete duplicate or invalid observers/observees, move the rest
from_user.as_observer_observation_links.where(user_id: target_user.as_observer_observation_links.map(&:user_id)).destroy_all
from_user.as_observer_observation_links.where(user_id: target_user).destroy_all
user_merge_data.add_more_data(target_user.as_observer_observation_links.where(user_id: from_user), user: target_user)
user_merge_data.add_more_data(target_user.as_observer_observation_links.where(user_id: from_user), user: target_user, data: data)
@data = []
target_user.as_observer_observation_links.where(user_id: from_user).destroy_all
from_user.as_observer_observation_links.update_all(observer_id: target_user.id)
xor_observer_ids = UserObservationLink.where(student: [from_user, target_user]).distinct.pluck(:observer_id)
Expand Down Expand Up @@ -316,11 +321,8 @@ def enrollment_keeper(scope)
END, updated_at DESC")).first
end

def update_enrollment_state(scope, keeper, user_merge_data)
# record both records state sicne both will change
user_merge_data.add_more_data(scope)
def update_enrollment_state(scope, keeper)
# update the record on the target user to the better state of the from users enrollment

enrollment_ids = Enrollment.where(id: scope).where.not(id: keeper).pluck(:id)
Enrollment.where(:id => enrollment_ids).update_all(workflow_state: keeper.workflow_state)
EnrollmentState.force_recalculation(enrollment_ids)
Expand All @@ -344,12 +346,16 @@ def handle_conflicts(column, target_user, user_merge_data)
to_update = scope.where.not(id: keeper).where(column => target_user)
# if the target_users enrollment state will be updated pass the scope so
# both target and from users records will be recorded in case of a split.
update_enrollment_state(scope, keeper, user_merge_data) if to_update.exists?
if to_update.exists?
# record both records state since both will change
user_merge_data.build_more_data(scope, data: data)
update_enrollment_state(scope, keeper)
end

# identify if the from users records are worse states than target user
to_delete = scope.active.where.not(id: keeper).where(column => from_user)
# record the current state in case of split
user_merge_data.add_more_data(to_delete)
user_merge_data.build_more_data(to_delete, data: data)
# mark all conflicts on from_user as deleted so they will not be moved later
to_delete.destroy_all
end
Expand All @@ -361,7 +367,7 @@ def remove_self_observers(target_user, user_merge_data)
(associated_user_id = :target_user AND user_id = :from_user OR
associated_user_id = :from_user AND user_id = :target_user)",
{target_user: target_user, from_user: from_user})
user_merge_data.add_more_data(to_delete)
user_merge_data.build_more_data(to_delete, data: data)
to_delete.destroy_all
end

Expand All @@ -371,14 +377,15 @@ def move_enrollments(target_user, user_merge_data)
Enrollment.transaction do
handle_conflicts(column, target_user, user_merge_data)
remove_self_observers(target_user, user_merge_data)

# move all the enrollments that have not been marked as deleted to the target user
to_move = Enrollment.active.where(column => from_user)
user_merge_data.add_more_data(to_move)
user_merge_data.build_more_data(to_move, data: data)
to_move.update_all(column => target_user.id)
end
end
end
user_merge_data.bulk_insert_merge_data(data)
@data = []
end

def handle_submissions(target_user, user_merge_data)
Expand All @@ -405,8 +412,8 @@ def handle_submissions(target_user, user_merge_data)
to_move_ids += scope.having_submission.select(unique_id).where.not(unique_id => already_scope.having_submission.select(unique_id), id: to_move_ids).pluck(:id)
to_move = scope.where(id: to_move_ids).to_a
move_back = already_scope.where(unique_id => to_move.map(&unique_id)).to_a
user_merge_data.add_more_data(to_move)
user_merge_data.add_more_data(move_back)
user_merge_data.build_more_data(to_move, data: data)
user_merge_data.build_more_data(move_back, data: data)
swap_submission(model, move_back, table, target_user, to_move, to_move_ids, 'fk_rails_8d85741475')
elsif model.name == "Quizzes::QuizSubmission"
subscope = already_scope.to_a
Expand All @@ -415,14 +422,16 @@ def handle_submissions(target_user, user_merge_data)

to_move += scope.where("#{unique_id} NOT IN (?)", [subscope.map(&unique_id), move_back.map(&unique_id)].flatten).to_a
move_back += already_scope.where(unique_id => to_move.map(&unique_id)).to_a
user_merge_data.add_more_data(to_move)
user_merge_data.add_more_data(move_back)
user_merge_data.build_more_data(to_move, data: data)
user_merge_data.build_more_data(move_back, data: data)
swap_submission(model, move_back, table, target_user, to_move, to_move, 'fk_rails_04850db4b4')
end
rescue => e
Rails.logger.error "migrating #{table} column user_id failed: #{e}"
end
end
user_merge_data.bulk_insert_merge_data(data)
@data = []
end

def swap_submission(model, move_back, table, target_user, to_move, to_move_ids, fk)
Expand Down

0 comments on commit f84d419

Please sign in to comment.