diff options
author | Alejandro Rodríguez <alejorro70@gmail.com> | 2016-06-20 19:20:08 -0400 |
---|---|---|
committer | Alejandro Rodríguez <alejorro70@gmail.com> | 2016-06-20 19:20:08 -0400 |
commit | ffcdc39d6d6334f0b7be1f78ae9daac1257fc857 (patch) | |
tree | 4094ace66f09623fff752af1658e18891fa8e59a | |
parent | 5804b6a0a28a20b1977ab89e04b15b85475b49e0 (diff) | |
download | gitlab-ce-18590-banzai-filter-relativelinkfilter-is-slow.tar.gz |
Optimize Banzai::Filter::RelativeLinkFilter18590-banzai-filter-relativelinkfilter-is-slow
A lot of git operations were being repeated, for example, to build a url
you would ask if the path was a Tree, which would call a recursive routine
in Gitlab::Git::Tree#where, then ask if the path was a Blob, which would
call a recursive routine at Gitlab::Git::Blob#find, making reference to
the same git objects several times. Now we call Rugged::Tree#path, which
allows us to determine the type of the path in one pass.
Some other minor improvement added, like saving commonly used references
instead of calculating them each time.
-rw-r--r-- | CHANGELOG | 3 | ||||
-rw-r--r-- | app/models/commit.rb | 24 | ||||
-rw-r--r-- | lib/banzai/filter/relative_link_filter.rb | 47 | ||||
-rw-r--r-- | spec/lib/banzai/filter/relative_link_filter_spec.rb | 7 | ||||
-rw-r--r-- | spec/models/commit_spec.rb | 12 |
5 files changed, 53 insertions, 40 deletions
diff --git a/CHANGELOG b/CHANGELOG index 3c80936468b..301ab0d5d36 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ Please view this file on the master branch, on stable branches it's out of date. +v 8.10.0 (unrelease) + - Performance improvements on RelativeLinkFilter + v 8.9.0 (unreleased) - Fix error when CI job variables key specified but not defined - Fix pipeline status when there are no builds in pipeline diff --git a/app/models/commit.rb b/app/models/commit.rb index d69d518fadd..5350856103d 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -271,6 +271,30 @@ class Commit merged_merge_request ? 'merge request' : 'commit' end + # Get the type of the given path + # + # path - String path to check + # + # Examples: + # + # path_type('doc/README.md') # => :blob + # path_type('doc/logo.png') # => :raw + # path_type('doc/api') # => :tree + # path_type('not/found') # => :nil + # + # Returns a symbol + def path_type(path) + entry = @raw.tree.path(path) + if entry[:type] == :blob + blob = Gitlab::Git::Blob.new(name: entry[:name]) + blob.image? ? :raw : :blob + else + entry[:type] + end + rescue Rugged::TreeError + nil + end + private def repo_changes diff --git a/lib/banzai/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb index ea21c7b041c..52c9b82fe7c 100644 --- a/lib/banzai/filter/relative_link_filter.rb +++ b/lib/banzai/filter/relative_link_filter.rb @@ -14,6 +14,8 @@ module Banzai def call return doc unless linkable_files? + @path_types = {} + doc.search('a:not(.gfm)').each do |el| process_link_attr el.attribute('href') end @@ -87,7 +89,7 @@ module Banzai return path unless request_path parts = request_path.split('/') - parts.pop if path_type(request_path) != 'tree' + parts.pop if path_type(request_path) != :tree while path.start_with?('../') parts.pop @@ -98,45 +100,20 @@ module Banzai end def file_exists?(path) - return false if path.nil? - repository.blob_at(current_sha, path).present? || - repository.tree(current_sha, path).entries.any? + path.present? && path_type(path) end - # Get the type of the given path - # - # path - String path to check - # - # Examples: - # - # path_type('doc/README.md') # => 'blob' - # path_type('doc/logo.png') # => 'raw' - # path_type('doc/api') # => 'tree' - # - # Returns a String def path_type(path) - unescaped_path = Addressable::URI.unescape(path) - - if tree?(unescaped_path) - 'tree' - elsif image?(unescaped_path) - 'raw' - else - 'blob' - end - end + @path_types[path] ||= begin + unescaped_path = Addressable::URI.unescape(path) - def tree?(path) - repository.tree(current_sha, path).entries.any? - end - - def image?(path) - repository.blob_at(current_sha, path).try(:image?) + current_commit.path_type(unescaped_path) + end end - def current_sha - context[:commit].try(:id) || - ref ? repository.commit(ref).try(:sha) : repository.head_commit.sha + def current_commit + @current_commit ||= context[:commit] || + ref ? repository.commit(ref) : repository.head_commit end def relative_url_root @@ -148,7 +125,7 @@ module Banzai end def repository - context[:project].try(:repository) + @repository ||= context[:project].try(:repository) end end end diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb index 0e6685f0ffb..14f159df0ed 100644 --- a/spec/lib/banzai/filter/relative_link_filter_spec.rb +++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb @@ -132,11 +132,8 @@ describe Banzai::Filter::RelativeLinkFilter, lib: true do path = 'files/images/한글.png' escaped = Addressable::URI.escape(path) - # Stub these methods so the file doesn't actually need to be in the repo - allow_any_instance_of(described_class). - to receive(:file_exists?).and_return(true) - allow_any_instance_of(described_class). - to receive(:image?).with(path).and_return(true) + # Stub this method so the file doesn't actually need to be in the repo + allow_any_instance_of(described_class).to receive(:path_type).and_return(:raw) doc = filter(image(escaped)) expect(doc.at_css('img')['src']).to match '/raw/' diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index beca8708c9d..f4744569df0 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -207,4 +207,16 @@ eos expect(commit.participants).to include(note1.author, note2.author) end end + + describe '#path_type' do + it 'returns the type of the object at the given path' do + expect(commit.path_type('files/html')).to be(:tree) + expect(commit.path_type('files/images/logo-black.png')).to be(:raw) + expect(commit.path_type('files/js/application.js')).to be(:blob) + end + + it "returns nil if the path doesn't exists" do + expect(commit.path_type('this/path/doesnt/exist')).to be_nil + end + end end |