Skip to content

Consider caching FindCommit call for the root ref

The FindCommit RPC is one of the most popular ones: https://log.gprd.gitlab.net/goto/2690d5a0-5f4d-11ed-b0ec-930003e0679c.

Let's investigate whether is possible to cache it for the root ref. If we decide that it's reasonable to introduce this optimization, it makes sense to do it behind a feature flag. The changes may look something like:

diff --git a/app/models/repository.rb b/app/models/repository.rb
index 3413b3e34249..8b3644385425 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -52,7 +52,7 @@ class Repository
                       gitlab_ci_yml branch_names tag_names branch_count
                       tag_count avatar exists? root_ref merged_branch_names
                       has_visible_content? issue_template_names_hash merge_request_template_names_hash
-                      user_defined_metrics_dashboard_paths xcode_project? has_ambiguous_refs?).freeze
+                      user_defined_metrics_dashboard_paths xcode_project? has_ambiguous_refs? root_ref_commit).freeze
 
   # Certain method caches should be refreshed when certain types of files are
   # changed. This Hash maps file types (as returned by Gitlab::FileDetector) to
@@ -361,6 +361,10 @@ def expire_statistics_caches
     expire_method_caches(%i(size commit_count))
   end
 
+  def expire_root_ref_commit_cache
+    expire_method_caches(%i(root_ref_commit))
+  end
+
   def expire_all_method_caches
     expire_method_caches(CACHED_METHODS)
   end
@@ -407,7 +411,7 @@ def expire_branch_cache(branch_name = nil)
   end
 
   def expire_root_ref_cache
-    expire_method_caches(%i(root_ref))
+    expire_method_caches(%i(root_ref root_ref_commit))
   end
 
   # Expires the cache(s) used to determine if a repository is empty or not.
@@ -430,6 +434,7 @@ def expire_content_cache
     expire_emptiness_caches
     expire_exists_cache
     expire_statistics_caches
+    expire_root_ref_commit_cache
   end
 
   def expire_status_cache
@@ -498,6 +503,7 @@ def after_change_head
 
   # Runs code after a new commit has been pushed.
   def after_push_commit(branch_name)
+    expire_root_ref_commit_cache
     expire_statistics_caches
     expire_branch_cache(branch_name)
 
@@ -1203,6 +1209,8 @@ def remove_prohibited_branches
   # TODO Genericize finder, later split this on finders by Ref or Oid
   # https://gitlab.com/gitlab-org/gitlab/issues/19877
   def find_commit(oid_or_ref)
+    return ::Commit.from_hash(root_ref_commit, container) if oid_or_ref == root_ref
+
     commit = if oid_or_ref.is_a?(Gitlab::Git::Commit)
                oid_or_ref
              else
@@ -1212,6 +1220,11 @@ def find_commit(oid_or_ref)
     ::Commit.new(commit, container) if commit
   end
 
+  def root_ref_commit
+    Gitlab::Git::Commit.find(raw_repository, root_ref).to_hash
+  end
+  cache_method_asymmetrically :root_ref_commit
+
   def redis_set_cache
     @redis_set_cache ||= Gitlab::RepositorySetCache.new(self)
   end