Commit ed06a211 authored by Yorick Peterse's avatar Yorick Peterse Committed by Robert Speicher

Merge branch '18663-avoid-extra-yaml-serializations' into 'master'

Use update_columns to by_pass all the dirty code on active_record

See merge request !4985
(cherry picked from commit ad09fcb5)
parent f3de17fd
...@@ -14,6 +14,7 @@ v 8.9.3 ...@@ -14,6 +14,7 @@ v 8.9.3
- Removed fade when filtering results. !4932 - Removed fade when filtering results. !4932
- Fix missing avatar on system notes. !4954 - Fix missing avatar on system notes. !4954
- Reduce overhead and optimize ProjectTeam#max_member_access performance. !4973 - Reduce overhead and optimize ProjectTeam#max_member_access performance. !4973
- Use update_columns to by_pass all the dirty code on active_record. !4985
v 8.9.2 v 8.9.2
- Fix visibility of snippets when searching. - Fix visibility of snippets when searching.
......
...@@ -108,44 +108,46 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -108,44 +108,46 @@ class MergeRequestDiff < ActiveRecord::Base
# Reload all commits related to current merge request from repo # Reload all commits related to current merge request from repo
# and save it as array of hashes in st_commits db field # and save it as array of hashes in st_commits db field
def reload_commits def reload_commits
new_attributes = {}
commit_objects = unmerged_commits commit_objects = unmerged_commits
if commit_objects.present? if commit_objects.present?
self.st_commits = dump_commits(commit_objects) new_attributes[:st_commits] = dump_commits(commit_objects)
end end
save update_columns_serialized(new_attributes)
end end
# Reload diffs between branches related to current merge request from repo # Reload diffs between branches related to current merge request from repo
# and save it as array of hashes in st_diffs db field # and save it as array of hashes in st_diffs db field
def reload_diffs def reload_diffs
new_attributes = {}
new_diffs = [] new_diffs = []
if commits.size.zero? if commits.size.zero?
self.state = :empty new_attributes[:state] = :empty
else else
diff_collection = unmerged_diffs diff_collection = unmerged_diffs
if diff_collection.overflow? if diff_collection.overflow?
# Set our state to 'overflow' to make the #empty? and #collected? # Set our state to 'overflow' to make the #empty? and #collected?
# methods (generated by StateMachine) return false. # methods (generated by StateMachine) return false.
self.state = :overflow new_attributes[:state] = :overflow
end end
self.real_size = diff_collection.real_size new_attributes[:real_size] = diff_collection.real_size
if diff_collection.any? if diff_collection.any?
new_diffs = dump_diffs(diff_collection) new_diffs = dump_diffs(diff_collection)
self.state = :collected new_attributes[:state] = :collected
end end
end end
self.st_diffs = new_diffs new_attributes[:st_diffs] = new_diffs
new_attributes[:base_commit_sha] = self.repository.merge_base(self.head, self.base)
self.base_commit_sha = self.repository.merge_base(self.head, self.base)
self.save update_columns_serialized(new_attributes)
end end
# Collect array of Git::Diff objects # Collect array of Git::Diff objects
...@@ -190,4 +192,29 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -190,4 +192,29 @@ class MergeRequestDiff < ActiveRecord::Base
) )
end end
end end
private
#
# #save or #update_attributes providing changes on serialized attributes do a lot of
# serialization and deserialization calls resulting in bad performance.
# Using #update_columns solves the problem with just one YAML.dump per serialized attribute that we provide.
# As a tradeoff we need to reload the current instance to properly manage time objects on those serialized
# attributes. So to keep the same behaviour as the attribute assignment we reload the instance.
# The difference is in the usage of
# #write_attribute= (#update_attributes) and #raw_write_attribute= (#update_columns)
#
# Ex:
#
# new_attributes[:st_commits].first.slice(:committed_date)
# => {:committed_date=>2014-02-27 11:01:38 +0200}
# YAML.load(YAML.dump(new_attributes[:st_commits].first.slice(:committed_date)))
# => {:committed_date=>2014-02-27 10:01:38 +0100}
#
def update_columns_serialized(new_attributes)
return unless new_attributes.any?
update_columns(new_attributes.merge(updated_at: current_time_from_proper_timezone))
reload
end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment