diff options
author | Yorick Peterse <yorickpeterse@gmail.com> | 2017-12-01 14:52:16 +0100 |
---|---|---|
committer | Yorick Peterse <yorickpeterse@gmail.com> | 2017-12-05 19:47:04 +0100 |
commit | c2dd98764d03dbdce9d0166ee53830e98972b459 (patch) | |
tree | 8863ef65a853a6fbd76e0ac28c03a98e442f054f /app/models/note.rb | |
parent | 4ca4b0ff702a68a9aed5da70d9170da410eefafa (diff) | |
download | gitlab-ce-throttle-touching-of-objects.tar.gz |
Throttle the number of UPDATEs triggered by touchthrottle-touching-of-objects
This throttles the number of UPDATE queries that can be triggered by
calling "touch" on a Note, Issue, or MergeRequest. For Note objects we
also take care of updating the associated "noteable" relation in a
smarter way than Rails does by default.
Diffstat (limited to 'app/models/note.rb')
-rw-r--r-- | app/models/note.rb | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/app/models/note.rb b/app/models/note.rb index 340fe087f82..581adabbb96 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -15,6 +15,7 @@ class Note < ActiveRecord::Base include IgnorableColumn include Editable include Gitlab::SQL::Pattern + include ThrottledTouch module SpecialRole FIRST_TIME_CONTRIBUTOR = :first_time_contributor @@ -55,7 +56,7 @@ class Note < ActiveRecord::Base participant :author belongs_to :project - belongs_to :noteable, polymorphic: true, touch: true # rubocop:disable Cop/PolymorphicAssociations + belongs_to :noteable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations belongs_to :author, class_name: "User" belongs_to :updated_by, class_name: "User" belongs_to :last_edited_by, class_name: 'User' @@ -118,6 +119,7 @@ class Note < ActiveRecord::Base before_validation :set_discussion_id, on: :create after_save :keep_around_commit, if: :for_project_noteable? after_save :expire_etag_cache + after_save :touch_noteable after_destroy :expire_etag_cache class << self @@ -367,6 +369,38 @@ class Note < ActiveRecord::Base Gitlab::EtagCaching::Store.new.touch(key) end + def touch(*args) + # We're not using an explicit transaction here because this would in all + # cases result in all future queries going to the primary, even if no writes + # are performed. + # + # We touch the noteable first so its SELECT query can run before our writes, + # ensuring it runs on a secondary (if no prior write took place). + touch_noteable + super + end + + # By default Rails will issue an "SELECT *" for the relation, which is an + # overkill for just updating the timestamps. To work around this we manually + # touch the data so we can SELECT only the columns we need. + def touch_noteable + # Commits are not stored in the DB so we can't touch them. + return if for_commit? + + assoc = association(:noteable) + + noteable_object = + if assoc.loaded? + noteable + else + # If the object is not loaded (e.g. when notes are loaded async) we + # _only_ want the data we actually need. + assoc.scope.select(:id, :updated_at).take + end + + noteable_object&.touch + end + private def keep_around_commit |