Merge branch 'perf.slow-issuable' into 'master'
Perf.slow issuable Closes #32844 See merge request !13685
This commit is contained in:
		
						commit
						fbab532fc1
					
				| 
						 | 
				
			
			@ -60,6 +60,10 @@ class Repository
 | 
			
		|||
    @project = project
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def ==(other)
 | 
			
		||||
    @disk_path == other.disk_path
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def raw_repository
 | 
			
		||||
    return nil unless full_path
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -75,6 +79,10 @@ class Repository
 | 
			
		|||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def inspect
 | 
			
		||||
    "#<#{self.class.name}:#{@disk_path}>"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  #
 | 
			
		||||
  # Git repository can contains some hidden refs like:
 | 
			
		||||
  #   /refs/notes/*
 | 
			
		||||
| 
						 | 
				
			
			@ -992,25 +1000,22 @@ class Repository
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def with_repo_branch_commit(start_repository, start_branch_name)
 | 
			
		||||
    return yield(nil) if start_repository.empty_repo?
 | 
			
		||||
    return yield nil if start_repository.empty_repo?
 | 
			
		||||
 | 
			
		||||
    branch_name_or_sha =
 | 
			
		||||
      if start_repository == self
 | 
			
		||||
        start_branch_name
 | 
			
		||||
    if start_repository == self
 | 
			
		||||
      yield commit(start_branch_name)
 | 
			
		||||
    else
 | 
			
		||||
      sha = start_repository.commit(start_branch_name).sha
 | 
			
		||||
 | 
			
		||||
      if branch_commit = commit(sha)
 | 
			
		||||
        yield branch_commit
 | 
			
		||||
      else
 | 
			
		||||
        tmp_ref = fetch_ref(
 | 
			
		||||
          start_repository.path_to_repo,
 | 
			
		||||
          "#{Gitlab::Git::BRANCH_REF_PREFIX}#{start_branch_name}",
 | 
			
		||||
          "refs/tmp/#{SecureRandom.hex}/head"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        start_repository.commit(start_branch_name).sha
 | 
			
		||||
        with_repo_tmp_commit(
 | 
			
		||||
          start_repository, start_branch_name, sha) do |tmp_commit|
 | 
			
		||||
          yield tmp_commit
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
    yield(commit(branch_name_or_sha))
 | 
			
		||||
 | 
			
		||||
  ensure
 | 
			
		||||
    rugged.references.delete(tmp_ref) if tmp_ref
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def add_remote(name, url)
 | 
			
		||||
| 
						 | 
				
			
			@ -1219,4 +1224,16 @@ class Repository
 | 
			
		|||
      .commits_by_message(query, revision: ref, path: path, limit: limit, offset: offset)
 | 
			
		||||
      .map { |c| commit(c) }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def with_repo_tmp_commit(start_repository, start_branch_name, sha)
 | 
			
		||||
    tmp_ref = fetch_ref(
 | 
			
		||||
      start_repository.path_to_repo,
 | 
			
		||||
      "#{Gitlab::Git::BRANCH_REF_PREFIX}#{start_branch_name}",
 | 
			
		||||
      "refs/tmp/#{SecureRandom.hex}/head"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    yield commit(sha)
 | 
			
		||||
  ensure
 | 
			
		||||
    rugged.references.delete(tmp_ref) if tmp_ref
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
---
 | 
			
		||||
title: Fix repository equality check and avoid fetching ref if the commit is already
 | 
			
		||||
  available. This affects merge request creation performance
 | 
			
		||||
merge_request: 13685
 | 
			
		||||
author:
 | 
			
		||||
type: other
 | 
			
		||||
| 
						 | 
				
			
			@ -923,13 +923,16 @@ describe Repository, models: true do
 | 
			
		|||
  describe '#update_branch_with_hooks' do
 | 
			
		||||
    let(:old_rev) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } # git rev-parse feature
 | 
			
		||||
    let(:new_rev) { 'a74ae73c1ccde9b974a70e82b901588071dc142a' } # commit whose parent is old_rev
 | 
			
		||||
    let(:updating_ref) { 'refs/heads/feature' }
 | 
			
		||||
    let(:target_project) { project }
 | 
			
		||||
    let(:target_repository) { target_project.repository }
 | 
			
		||||
 | 
			
		||||
    context 'when pre hooks were successful' do
 | 
			
		||||
      before do
 | 
			
		||||
        service = Gitlab::Git::HooksService.new
 | 
			
		||||
        expect(Gitlab::Git::HooksService).to receive(:new).and_return(service)
 | 
			
		||||
        expect(service).to receive(:execute)
 | 
			
		||||
          .with(committer, repository, old_rev, new_rev, 'refs/heads/feature')
 | 
			
		||||
          .with(committer, target_repository, old_rev, new_rev, updating_ref)
 | 
			
		||||
          .and_yield(service).and_return(true)
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -960,6 +963,37 @@ describe Repository, models: true do
 | 
			
		|||
          expect(repository.find_branch('feature').dereferenced_target.id).to eq(new_rev)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      context 'when target project does not have the commit' do
 | 
			
		||||
        let(:target_project) { create(:project, :empty_repo) }
 | 
			
		||||
        let(:old_rev) { Gitlab::Git::BLANK_SHA }
 | 
			
		||||
        let(:new_rev) { project.commit('feature').sha }
 | 
			
		||||
        let(:updating_ref) { 'refs/heads/master' }
 | 
			
		||||
 | 
			
		||||
        it 'fetch_ref and create the branch' do
 | 
			
		||||
          expect(target_project.repository).to receive(:fetch_ref)
 | 
			
		||||
            .and_call_original
 | 
			
		||||
 | 
			
		||||
          GitOperationService.new(committer, target_repository)
 | 
			
		||||
            .with_branch(
 | 
			
		||||
              'master',
 | 
			
		||||
              start_project: project,
 | 
			
		||||
              start_branch_name: 'feature') { new_rev }
 | 
			
		||||
 | 
			
		||||
          expect(target_repository.branch_names).to contain_exactly('master')
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      context 'when target project already has the commit' do
 | 
			
		||||
        let(:target_project) { create(:project, :repository) }
 | 
			
		||||
 | 
			
		||||
        it 'does not fetch_ref and just pass the commit' do
 | 
			
		||||
          expect(target_repository).not_to receive(:fetch_ref)
 | 
			
		||||
 | 
			
		||||
          GitOperationService.new(committer, target_repository)
 | 
			
		||||
            .with_branch('feature', start_project: project) { new_rev }
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    context 'when temporary ref failed to be created from other project' do
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue