gitlab-org--gitlab-foss/lib/gitlab/git_post_receive.rb
Stan Hu f14647fdae Expire project caches once per push instead of once per ref
Previously `ProjectCacheWorker` would be scheduled once per ref, which
would generate unnecessary I/O and load on Sidekiq, especially if many
tags or branches were pushed at once. `ProjectCacheWorker` would expire
three items:

1. Repository size: This only needs to be updated once per push.
2. Commit count: This only needs to be updated if the default branch
   is updated.
3. Project method caches: This only needs to be updated if the default
   branch changes, but only if certain files change (e.g. README,
   CHANGELOG, etc.).

Because the third item requires looking at the actual changes in the
commit deltas, we schedule one `ProjectCacheWorker` to handle the first
two cases, and schedule a separate `ProjectCacheWorker` for the third
case if it is needed. As a result, this brings down the number of
`ProjectCacheWorker` jobs from N to 2.

Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/52046
2019-08-16 19:53:56 +00:00

70 lines
1.8 KiB
Ruby

# frozen_string_literal: true
module Gitlab
class GitPostReceive
include Gitlab::Identifier
attr_reader :project, :identifier, :changes, :push_options
def initialize(project, identifier, changes, push_options = {})
@project = project
@identifier = identifier
@changes = deserialize_changes(changes)
@push_options = push_options
end
def identify
super(identifier)
end
def changes_refs
return changes unless block_given?
changes.each do |change|
change.strip!
oldrev, newrev, ref = change.split(' ')
yield oldrev, newrev, ref
end
end
def includes_branches?
enum_for(:changes_refs).any? do |_oldrev, _newrev, ref|
Gitlab::Git.branch_ref?(ref)
end
end
def includes_tags?
enum_for(:changes_refs).any? do |_oldrev, _newrev, ref|
Gitlab::Git.tag_ref?(ref)
end
end
def includes_default_branch?
# If the branch doesn't have a default branch yet, we presume the
# first branch pushed will be the default.
return true unless project.default_branch.present?
enum_for(:changes_refs).any? do |_oldrev, _newrev, ref|
Gitlab::Git.branch_ref?(ref) &&
Gitlab::Git.branch_name(ref) == project.default_branch
end
end
private
def deserialize_changes(changes)
utf8_encode_changes(changes).each_line
end
def utf8_encode_changes(changes)
changes.force_encoding('UTF-8')
return changes if changes.valid_encoding?
# Convert non-UTF-8 branch/tag names to UTF-8 so they can be dumped as JSON.
detection = CharlockHolmes::EncodingDetector.detect(changes)
return changes unless detection && detection[:encoding]
CharlockHolmes::Converter.convert(changes, detection[:encoding], 'UTF-8')
end
end
end