diff options
Diffstat (limited to 'internal/gitaly/service/repository/create.go')
-rw-r--r-- | internal/gitaly/service/repository/create.go | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/internal/gitaly/service/repository/create.go b/internal/gitaly/service/repository/create.go index 59ff6aabf..118c95526 100644 --- a/internal/gitaly/service/repository/create.go +++ b/internal/gitaly/service/repository/create.go @@ -3,11 +3,17 @@ package repository import ( "bytes" "context" + "fmt" "os" "gitlab.com/gitlab-org/gitaly/internal/git" + "gitlab.com/gitlab-org/gitaly/internal/gitaly/transaction" "gitlab.com/gitlab-org/gitaly/internal/helper" + "gitlab.com/gitlab-org/gitaly/internal/transaction/txinfo" + "gitlab.com/gitlab-org/gitaly/internal/transaction/voting" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) func (s *server) CreateRepository(ctx context.Context, req *gitalypb.CreateRepositoryRequest) (*gitalypb.CreateRepositoryResponse, error) { @@ -40,5 +46,39 @@ func (s *server) CreateRepository(ctx context.Context, req *gitalypb.CreateRepos return nil, helper.ErrInternalf("git init stderr: %q, err: %w", stderr, err) } + // Given that git-init(1) does not create any refs, we never cast a vote on it. We thus do + // manual voting here by hashing all references of the repository. While this would in the + // general case hash nothing given that no refs exist yet, due to the idempotency of this + // RPC it may be that we already do have some preexisting refs (e.g. CreateRepository is + // called for a repo which already exists and has refs). In that case, voting ensures that + // all replicas have the same set of preexisting refs. + if err := transaction.RunOnContext(ctx, func(tx txinfo.Transaction, server txinfo.PraefectServer) error { + hash := voting.NewVoteHash() + + cmd, err := s.gitCmdFactory.New(ctx, req.GetRepository(), git.SubCmd{ + Name: "for-each-ref", + }, git.WithStdout(hash)) + if err != nil { + return fmt.Errorf("for-each-ref: %v", err) + } + + if err := cmd.Wait(); err != nil { + return fmt.Errorf("waiting for for-each-ref: %v", err) + } + + vote, err := hash.Vote() + if err != nil { + return err + } + + if err := s.txManager.Vote(ctx, tx, server, vote); err != nil { + return fmt.Errorf("casting vote: %w", err) + } + + return nil + }); err != nil { + return nil, status.Errorf(codes.Aborted, "vote failed after initializing repo: %v", err) + } + return &gitalypb.CreateRepositoryResponse{}, nil } |