summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Hu <stanhu@gmail.com>2019-08-13 09:04:30 -0700
committerStan Hu <stanhu@gmail.com>2019-08-13 09:04:30 -0700
commite658f9603c99ca6a8ef4c0292b2cdab2916fb09e (patch)
tree57e0c03ea5dd676c7a53243bf3da20aefafc0ded
parent3702ab7317533896c7455357dd6643181666f22b (diff)
downloadgitlab-ce-sh-only-flush-tags-once-per-push.tar.gz
Only expire tag cache once per pushsh-only-flush-tags-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
-rw-r--r--app/models/repository.rb14
-rw-r--r--app/workers/post_receive.rb2
-rw-r--r--changelogs/unreleased/sh-only-flush-tags-once-per-push.yml5
-rw-r--r--lib/gitlab/git_post_receive.rb6
-rw-r--r--spec/lib/gitlab/git_post_receive_spec.rb43
-rw-r--r--spec/models/repository_spec.rb13
-rw-r--r--spec/services/git/tag_push_service_spec.rb4
-rw-r--r--spec/workers/post_receive_spec.rb30
8 files changed, 105 insertions, 12 deletions
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 58abfaef801..9d45a12fa6e 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -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.
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index d8dfbc0faf7..675fa1a73ca 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -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 =
diff --git a/changelogs/unreleased/sh-only-flush-tags-once-per-push.yml b/changelogs/unreleased/sh-only-flush-tags-once-per-push.yml
new file mode 100644
index 00000000000..502fc22ebbd
--- /dev/null
+++ b/changelogs/unreleased/sh-only-flush-tags-once-per-push.yml
@@ -0,0 +1,5 @@
+---
+title: Only expire tag cache once per push
+merge_request: 31641
+author:
+type: performance
diff --git a/lib/gitlab/git_post_receive.rb b/lib/gitlab/git_post_receive.rb
index 6c7f23a673c..24d752b8a4b 100644
--- a/lib/gitlab/git_post_receive.rb
+++ b/lib/gitlab/git_post_receive.rb
@@ -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)
diff --git a/spec/lib/gitlab/git_post_receive_spec.rb b/spec/lib/gitlab/git_post_receive_spec.rb
index 1911e954df9..4c20d945585 100644
--- a/spec/lib/gitlab/git_post_receive_spec.rb
+++ b/spec/lib/gitlab/git_post_receive_spec.rb
@@ -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
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index fa243876632..e68de2e73a8 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -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
diff --git a/spec/services/git/tag_push_service_spec.rb b/spec/services/git/tag_push_service_spec.rb
index 418952b52da..7e008637182 100644
--- a/spec/services/git/tag_push_service_spec.rb
+++ b/spec/services/git/tag_push_service_spec.rb
@@ -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
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 081d95d4d79..c586ee3006e 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -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