Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <psteinhardt@gitlab.com>2021-01-06 18:04:44 +0300
committerPatrick Steinhardt <psteinhardt@gitlab.com>2021-01-07 09:53:39 +0300
commit05d856ae3190be03391e4d15e6b390ecd9321c65 (patch)
tree549daa75ad6a20cb1d5d0a6be8fa16fe36eadc49
parentf8fc985805eaf7cf53a910c47d18f1573d2f439e (diff)
repository: Skip fetch if the object exists already
When executing `FetchSourceBranch()`, then we can quite easily optimize away the fetch in case we know that the desired object exists in the target repository already. There's basically two cases: - When source and target repository are the same, then we can always optimize away the fetch. - When source and target repository are different repositories, we can still optimize away the fetch in some cases as we resolve the object's ID beforehand anyway. While the first optimization exists already, the second doesn't. So let's add it.
-rw-r--r--changelogs/unreleased/pks-fetch-source-branch-short-circuits.yml5
-rw-r--r--internal/gitaly/service/repository/fetch.go47
2 files changed, 44 insertions, 8 deletions
diff --git a/changelogs/unreleased/pks-fetch-source-branch-short-circuits.yml b/changelogs/unreleased/pks-fetch-source-branch-short-circuits.yml
new file mode 100644
index 000000000..af1d64246
--- /dev/null
+++ b/changelogs/unreleased/pks-fetch-source-branch-short-circuits.yml
@@ -0,0 +1,5 @@
+---
+title: 'repository: Short-circuit fetches when objects exist already'
+merge_request: 2980
+author:
+type: performance
diff --git a/internal/gitaly/service/repository/fetch.go b/internal/gitaly/service/repository/fetch.go
index 58d58a310..62aa94e02 100644
--- a/internal/gitaly/service/repository/fetch.go
+++ b/internal/gitaly/service/repository/fetch.go
@@ -34,17 +34,48 @@ func (s *server) FetchSourceBranch(ctx context.Context, req *gitalypb.FetchSourc
return nil, helper.ErrInternal(err)
}
- sourceOid, err := sourceRepo.ResolveRefish(ctx, string(req.GetSourceBranch()))
- if err != nil {
- if errors.Is(err, git.ErrReferenceNotFound) {
- return &gitalypb.FetchSourceBranchResponse{Result: false}, nil
+ var sourceOid string
+ var containsObject bool
+
+ // If source and target repository are the same, then we know that both
+ // are local. We can thus optimize and locally resolve the reference
+ // instead of using an RPC call. We also know that we can always skip
+ // the fetch as the object will be available.
+ if helper.RepoPathEqual(req.GetRepository(), req.GetSourceRepository()) {
+ var err error
+
+ sourceOid, err = targetRepo.ResolveRefish(ctx, string(req.GetSourceBranch()))
+ if err != nil {
+ if errors.Is(err, git.ErrReferenceNotFound) {
+ return &gitalypb.FetchSourceBranchResponse{Result: false}, nil
+ }
+ return nil, helper.ErrInternal(err)
+ }
+
+ containsObject = true
+ } else {
+ var err error
+
+ sourceOid, err = sourceRepo.ResolveRefish(ctx, string(req.GetSourceBranch()))
+ if err != nil {
+ if errors.Is(err, git.ErrReferenceNotFound) {
+ return &gitalypb.FetchSourceBranchResponse{Result: false}, nil
+ }
+ return nil, helper.ErrInternal(err)
+ }
+
+ // Otherwise, if the source is a remote repository, we check
+ // whether the target repo already contains the desired object.
+ // If so, we can skip the fetch.
+ containsObject, err = targetRepo.ContainsRef(ctx, sourceOid+"^{commit}")
+ if err != nil {
+ return nil, helper.ErrInternal(err)
}
- return nil, helper.ErrInternal(err)
}
- // In case source and target repository refer to the same repository,
- // then we can simply skip the fetch.
- if !helper.RepoPathEqual(req.GetRepository(), req.GetSourceRepository()) {
+ // There's no need to perform the fetch if we already have the object
+ // available.
+ if !containsObject {
env, err := gitalyssh.UploadPackEnv(ctx, &gitalypb.SSHUploadPackRequest{Repository: req.SourceRepository})
if err != nil {
return nil, err