Only expire tag cache once per push
Previously each tag in a push would invoke the Gitaly `FindAllTags` RPC since the tag cache would be invalidated with every tag. We can eliminate those extraneous calls by expiring the tag cache once in `PostReceive` and taking advantage of the cached tags. Relates to https://gitlab.com/gitlab-org/gitlab-ce/issues/65795
This commit is contained in:
parent
3702ab7317
commit
e658f9603c
|
@ -418,25 +418,29 @@ class Repository
|
|||
end
|
||||
|
||||
# Runs code before pushing (= creating or removing) a tag.
|
||||
#
|
||||
# Note that this doesn't expire the tags. You may need to call
|
||||
# expire_caches_for_tags or expire_tags_cache.
|
||||
def before_push_tag
|
||||
repository_event(:push_tag)
|
||||
end
|
||||
|
||||
def expire_caches_for_tags
|
||||
expire_statistics_caches
|
||||
expire_emptiness_caches
|
||||
expire_tags_cache
|
||||
|
||||
repository_event(:push_tag)
|
||||
end
|
||||
|
||||
# Runs code before removing a tag.
|
||||
def before_remove_tag
|
||||
expire_tags_cache
|
||||
expire_statistics_caches
|
||||
expire_caches_for_tags
|
||||
|
||||
repository_event(:remove_tag)
|
||||
end
|
||||
|
||||
# Runs code after removing a tag.
|
||||
def after_remove_tag
|
||||
expire_tags_cache
|
||||
expire_caches_for_tags
|
||||
end
|
||||
|
||||
# Runs code after the HEAD of a repository is changed.
|
||||
|
|
|
@ -44,6 +44,8 @@ class PostReceive
|
|||
|
||||
# Expire the branches cache so we have updated data for this push
|
||||
post_received.project.repository.expire_branches_cache if post_received.includes_branches?
|
||||
# We only need to expire tags once per push
|
||||
post_received.project.repository.expire_caches_for_tags if post_received.includes_tags?
|
||||
|
||||
post_received.enum_for(:changes_refs).with_index do |(oldrev, newrev, ref), index|
|
||||
service_klass =
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Only expire tag cache once per push
|
||||
merge_request: 31641
|
||||
author:
|
||||
type: performance
|
|
@ -33,6 +33,12 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
def includes_tags?
|
||||
enum_for(:changes_refs).any? do |_oldrev, _newrev, ref|
|
||||
Gitlab::Git.tag_ref?(ref)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def deserialize_changes(changes)
|
||||
|
|
|
@ -49,4 +49,47 @@ describe ::Gitlab::GitPostReceive do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#includes_tags?' do
|
||||
context 'with no tags' do
|
||||
let(:changes) do
|
||||
<<~EOF
|
||||
654321 210987 refs/notags/tag1
|
||||
654322 210986 refs/heads/test1
|
||||
654323 210985 refs/merge-requests/mr1
|
||||
EOF
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(subject.includes_tags?).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
context 'with tags' do
|
||||
let(:changes) do
|
||||
<<~EOF
|
||||
654322 210986 refs/heads/test1
|
||||
654321 210987 refs/tags/tag1
|
||||
654323 210985 refs/merge-requests/mr1
|
||||
EOF
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(subject.includes_tags?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'with malformed changes' do
|
||||
let(:changes) do
|
||||
<<~EOF
|
||||
ref/tags/1 a
|
||||
sometag refs/tags/2
|
||||
EOF
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(subject.includes_tags?).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1744,12 +1744,23 @@ describe Repository do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#before_push_tag' do
|
||||
describe '#expires_caches_for_tags' do
|
||||
it 'flushes the cache' do
|
||||
expect(repository).to receive(:expire_statistics_caches)
|
||||
expect(repository).to receive(:expire_emptiness_caches)
|
||||
expect(repository).to receive(:expire_tags_cache)
|
||||
|
||||
repository.expire_caches_for_tags
|
||||
end
|
||||
end
|
||||
|
||||
describe '#before_push_tag' do
|
||||
it 'logs an event' do
|
||||
expect(repository).not_to receive(:expire_statistics_caches)
|
||||
expect(repository).not_to receive(:expire_emptiness_caches)
|
||||
expect(repository).not_to receive(:expire_tags_cache)
|
||||
expect(repository).to receive(:repository_event).with(:push_tag)
|
||||
|
||||
repository.before_push_tag
|
||||
end
|
||||
end
|
||||
|
|
|
@ -26,8 +26,8 @@ describe Git::TagPushService do
|
|||
subject
|
||||
end
|
||||
|
||||
it 'flushes the tags cache' do
|
||||
expect(project.repository).to receive(:expire_tags_cache)
|
||||
it 'does not flush the tags cache' do
|
||||
expect(project.repository).not_to receive(:expire_tags_cache)
|
||||
|
||||
subject
|
||||
end
|
||||
|
|
|
@ -85,8 +85,20 @@ describe PostReceive do
|
|||
end
|
||||
end
|
||||
|
||||
context 'tags' do
|
||||
let(:changes) { '123456 789012 refs/tags/tag' }
|
||||
context "tags" do
|
||||
let(:changes) do
|
||||
<<~EOF
|
||||
654321 210987 refs/tags/tag1
|
||||
654322 210986 refs/tags/tag2
|
||||
654323 210985 refs/tags/tag3
|
||||
654324 210984 refs/tags/tag4
|
||||
654325 210983 refs/tags/tag5
|
||||
EOF
|
||||
end
|
||||
|
||||
before do
|
||||
expect(Gitlab::GlRepository).to receive(:parse).and_return([project, Gitlab::GlRepository::PROJECT])
|
||||
end
|
||||
|
||||
it 'does not expire branches cache' do
|
||||
expect(project.repository).not_to receive(:expire_branches_cache)
|
||||
|
@ -94,8 +106,18 @@ describe PostReceive do
|
|||
described_class.new.perform(gl_repository, key_id, base64_changes)
|
||||
end
|
||||
|
||||
it 'calls Git::TagPushService' do
|
||||
expect_next_instance_of(Git::TagPushService) do |service|
|
||||
it "only invalidates tags once" do
|
||||
expect(project.repository).to receive(:repository_event).exactly(5).times.with(:push_tag).and_call_original
|
||||
expect(project.repository).to receive(:expire_caches_for_tags).once.and_call_original
|
||||
expect(project.repository).to receive(:expire_tags_cache).once.and_call_original
|
||||
|
||||
described_class.new.perform(gl_repository, key_id, base64_changes)
|
||||
end
|
||||
|
||||
it "calls Git::TagPushService" do
|
||||
expect(Git::BranchPushService).not_to receive(:new)
|
||||
|
||||
expect_any_instance_of(Git::TagPushService) do |service|
|
||||
expect(service).to receive(:execute).and_return(true)
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue