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>2022-07-22 12:45:33 +0300
committerPatrick Steinhardt <psteinhardt@gitlab.com>2022-07-27 16:24:16 +0300
commit311ead61e8592316a858f95086fc22527443ab3e (patch)
tree7a804c397099caaf5831368f68aa33768a373d3f
parent87d3de23b26a1a0f28a1aa2dd2aa2b1a72ccccde (diff)
objectpool: Demonstrate D/F conflicts in FetchIntoObjectPool
It is possible to get into a situation where FetchIntoObjectPool consistently fails because of conflicting references in the pool repository and the pool member we're fetching from. Add a testcase which demonstrates this issue.
-rw-r--r--internal/gitaly/service/objectpool/fetch_into_object_pool_test.go54
1 files changed, 54 insertions, 0 deletions
diff --git a/internal/gitaly/service/objectpool/fetch_into_object_pool_test.go b/internal/gitaly/service/objectpool/fetch_into_object_pool_test.go
index 8efae9056..6018ae32b 100644
--- a/internal/gitaly/service/objectpool/fetch_into_object_pool_test.go
+++ b/internal/gitaly/service/objectpool/fetch_into_object_pool_test.go
@@ -22,6 +22,7 @@ import (
"gitlab.com/gitlab-org/gitaly/v15/internal/git/housekeeping"
"gitlab.com/gitlab-org/gitaly/v15/internal/gitaly/config"
"gitlab.com/gitlab-org/gitaly/v15/internal/gitaly/transaction"
+ "gitlab.com/gitlab-org/gitaly/v15/internal/helper"
"gitlab.com/gitlab-org/gitaly/v15/internal/metadata"
"gitlab.com/gitlab-org/gitaly/v15/internal/testhelper"
"gitlab.com/gitlab-org/gitaly/v15/internal/testhelper/testcfg"
@@ -323,3 +324,56 @@ func TestFetchIntoObjectPool_Failure(t *testing.T) {
})
}
}
+
+func TestFetchIntoObjectPool_dfConflict(t *testing.T) {
+ t.Parallel()
+
+ ctx := testhelper.Context(t)
+ cfg, repo, repoPath, _, client := setup(ctx, t)
+
+ pool := initObjectPool(t, cfg, cfg.Storages[0])
+ _, err := client.CreateObjectPool(ctx, &gitalypb.CreateObjectPoolRequest{
+ ObjectPool: pool.ToProto(),
+ Origin: repo,
+ })
+ require.NoError(t, err)
+
+ gittest.WriteCommit(t, cfg, repoPath, gittest.WithBranch("branch"))
+
+ // Perform an initial fetch into the object pool with the given object that exists in the
+ // pool member's repository.
+ _, err = client.FetchIntoObjectPool(ctx, &gitalypb.FetchIntoObjectPoolRequest{
+ ObjectPool: pool.ToProto(),
+ Origin: repo,
+ })
+ require.NoError(t, err)
+
+ // Now we delete the reference in the pool member and create a new reference that has the
+ // same prefix, but is stored in a subdirectory. This will create a D/F conflict.
+ gittest.Exec(t, cfg, "-C", repoPath, "update-ref", "-d", "refs/heads/branch")
+ gittest.WriteCommit(t, cfg, repoPath, gittest.WithBranch("branch/conflict"))
+
+ gitVersion, err := gittest.NewCommandFactory(t, cfg).GitVersion(ctx)
+ require.NoError(t, err)
+
+ // Due to a bug in old Git versions we may get an unexpected exit status.
+ expectedExitStatus := 254
+ if !gitVersion.FlushesUpdaterefStatus() {
+ expectedExitStatus = 1
+ }
+
+ // Verify that we can still fetch into the object pool regardless of the D/F conflict. While
+ // it is not possible to store both references at the same time due to the conflict, we
+ // should know to delete the old conflicting reference and replace it with the new one.
+ _, err = client.FetchIntoObjectPool(ctx, &gitalypb.FetchIntoObjectPoolRequest{
+ ObjectPool: pool.ToProto(),
+ Origin: repo,
+ })
+
+ // But right now it fails due to a bug.
+ testhelper.RequireGrpcError(t, helper.ErrInternalf(
+ "fetch into object pool: exit status %d, stderr: %q",
+ expectedExitStatus,
+ "error: cannot lock ref 'refs/remotes/origin/heads/branch/conflict': 'refs/remotes/origin/heads/branch' exists; cannot create 'refs/remotes/origin/heads/branch/conflict'\n",
+ ), err)
+}