Bring back Rugged implementation of TreeEntry
This brings back some of the changes in https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20099/diffs For users using Gitaly on top of NFS, accessing the Git data directly via Rugged is more performant than Gitaly. This merge request introduces the feature flag `rugged_tree_entry` to activate the Rugged method. Part of four Rugged changes identified in https://gitlab.com/gitlab-org/gitlab-ce/issues/57317.
This commit is contained in:
parent
28883d8e44
commit
9d3e413aa7
4 changed files with 132 additions and 1 deletions
5
changelogs/unreleased/sh-rugged-get-tree-entry.yml
Normal file
5
changelogs/unreleased/sh-rugged-get-tree-entry.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Bring back Rugged implementation of TreeEntry
|
||||||
|
merge_request: 25706
|
||||||
|
author:
|
||||||
|
type: other
|
|
@ -23,6 +23,10 @@ module Gitlab
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def find(repository, sha, path, limit: MAX_DATA_DISPLAY_SIZE)
|
def find(repository, sha, path, limit: MAX_DATA_DISPLAY_SIZE)
|
||||||
|
tree_entry(repository, sha, path, limit)
|
||||||
|
end
|
||||||
|
|
||||||
|
def tree_entry(repository, sha, path, limit)
|
||||||
return unless path
|
return unless path
|
||||||
|
|
||||||
path = path.sub(%r{\A/*}, '')
|
path = path.sub(%r{\A/*}, '')
|
||||||
|
@ -179,3 +183,5 @@ module Gitlab
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Gitlab::Git::Blob.singleton_class.prepend Gitlab::Git::RuggedImpl::Blob::ClassMethods
|
||||||
|
|
106
lib/gitlab/git/rugged_impl/blob.rb
Normal file
106
lib/gitlab/git/rugged_impl/blob.rb
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# NOTE: This code is legacy. Do not add/modify code here unless you have
|
||||||
|
# discussed with the Gitaly team. See
|
||||||
|
# https://docs.gitlab.com/ee/development/gitaly.html#legacy-rugged-code
|
||||||
|
# for more details.
|
||||||
|
|
||||||
|
module Gitlab
|
||||||
|
module Git
|
||||||
|
module RuggedImpl
|
||||||
|
module Blob
|
||||||
|
module ClassMethods
|
||||||
|
extend ::Gitlab::Utils::Override
|
||||||
|
|
||||||
|
override :tree_entry
|
||||||
|
def tree_entry(repository, sha, path, limit)
|
||||||
|
if Feature.enabled?(:rugged_tree_entry)
|
||||||
|
rugged_tree_entry(repository, sha, path, limit)
|
||||||
|
else
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def rugged_tree_entry(repository, sha, path, limit)
|
||||||
|
return unless path
|
||||||
|
|
||||||
|
# Strip any leading / characters from the path
|
||||||
|
path = path.sub(%r{\A/*}, '')
|
||||||
|
|
||||||
|
rugged_commit = repository.lookup(sha)
|
||||||
|
root_tree = rugged_commit.tree
|
||||||
|
|
||||||
|
blob_entry = find_entry_by_path(repository, root_tree.oid, *path.split('/'))
|
||||||
|
|
||||||
|
return nil unless blob_entry
|
||||||
|
|
||||||
|
if blob_entry[:type] == :commit
|
||||||
|
submodule_blob(blob_entry, path, sha)
|
||||||
|
else
|
||||||
|
blob = repository.lookup(blob_entry[:oid])
|
||||||
|
|
||||||
|
if blob
|
||||||
|
new(
|
||||||
|
id: blob.oid,
|
||||||
|
name: blob_entry[:name],
|
||||||
|
size: blob.size,
|
||||||
|
# Rugged::Blob#content is expensive; don't call it if we don't have to.
|
||||||
|
data: limit.zero? ? '' : blob.content(limit),
|
||||||
|
mode: blob_entry[:filemode].to_s(8),
|
||||||
|
path: path,
|
||||||
|
commit_id: sha,
|
||||||
|
binary: blob.binary?
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue Rugged::ReferenceError
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# Recursive search of blob id by path
|
||||||
|
#
|
||||||
|
# Ex.
|
||||||
|
# blog/ # oid: 1a
|
||||||
|
# app/ # oid: 2a
|
||||||
|
# models/ # oid: 3a
|
||||||
|
# file.rb # oid: 4a
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Blob.find_entry_by_path(repo, '1a', 'blog', 'app', 'file.rb') # => '4a'
|
||||||
|
#
|
||||||
|
def find_entry_by_path(repository, root_id, *path_parts)
|
||||||
|
root_tree = repository.lookup(root_id)
|
||||||
|
|
||||||
|
entry = root_tree.find do |entry|
|
||||||
|
entry[:name] == path_parts[0]
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil unless entry
|
||||||
|
|
||||||
|
if path_parts.size > 1
|
||||||
|
return nil unless entry[:type] == :tree
|
||||||
|
|
||||||
|
path_parts.shift
|
||||||
|
find_entry_by_path(repository, entry[:oid], *path_parts)
|
||||||
|
else
|
||||||
|
[:blob, :commit].include?(entry[:type]) ? entry : nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def submodule_blob(blob_entry, path, sha)
|
||||||
|
new(
|
||||||
|
id: blob_entry[:oid],
|
||||||
|
name: blob_entry[:name],
|
||||||
|
size: 0,
|
||||||
|
data: '',
|
||||||
|
path: path,
|
||||||
|
commit_id: sha
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -18,7 +18,7 @@ describe Gitlab::Git::Blob, :seed_helper do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.find' do
|
shared_examples '.find' do
|
||||||
context 'nil path' do
|
context 'nil path' do
|
||||||
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, nil) }
|
let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, nil) }
|
||||||
|
|
||||||
|
@ -128,6 +128,20 @@ describe Gitlab::Git::Blob, :seed_helper do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.find with Gitaly enabled' do
|
||||||
|
it_behaves_like '.find'
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.find with Rugged enabled', :enable_rugged do
|
||||||
|
it 'calls out to the Rugged implementation' do
|
||||||
|
allow_any_instance_of(Rugged).to receive(:rev_parse).with(SeedRepo::Commit::ID).and_call_original
|
||||||
|
|
||||||
|
described_class.find(repository, SeedRepo::Commit::ID, 'files/images/6049019_460s.jpg')
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like '.find'
|
||||||
|
end
|
||||||
|
|
||||||
describe '.raw' do
|
describe '.raw' do
|
||||||
let(:raw_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::RubyBlob::ID) }
|
let(:raw_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::RubyBlob::ID) }
|
||||||
let(:bad_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::BigCommit::ID) }
|
let(:bad_blob) { Gitlab::Git::Blob.raw(repository, SeedRepo::BigCommit::ID) }
|
||||||
|
|
Loading…
Reference in a new issue