1package info 2 3import ( 4 "context" 5 6 "gitlab.com/gitlab-org/gitaly/v14/internal/helper" 7 "gitlab.com/gitlab-org/gitaly/v14/internal/praefect/config" 8 "gitlab.com/gitlab-org/gitaly/v14/internal/praefect/datastore" 9 "gitlab.com/gitlab-org/gitaly/v14/internal/praefect/nodes" 10 "gitlab.com/gitlab-org/gitaly/v14/internal/praefect/service" 11 "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb" 12) 13 14// AssignmentStore is an interface for getting repository host node assignments. 15// 16// This duplicates the praefect.AssignmentGetter type as it is not possible to import anything from 17// `praefect` to `info` packages due to cyclic dependencies. 18type AssignmentStore interface { 19 // GetHostAssignments returns the names of the storages assigned to host the repository. 20 // The primary node must always be assigned. 21 GetHostAssignments(ctx context.Context, virtualStorage, relativePath string) ([]string, error) 22 // SetReplicationFactor sets a repository's replication factor and returns the current assignments. 23 SetReplicationFactor(ctx context.Context, virtualStorage, relativePath string, replicationFactor int) ([]string, error) 24} 25 26// PrimaryGetter is an interface for getting a primary of a repository. 27// 28// This duplicates the praefect.PrimaryGetter type as it is not possible to import anything from 29// `praefect` to `info` packages due to cyclic dependencies. 30type PrimaryGetter interface { 31 // GetPrimary returns the primary storage for a given repository. 32 GetPrimary(ctx context.Context, virtualStorage string, relativePath string) (string, error) 33} 34 35// Server is a InfoService server 36type Server struct { 37 nodeMgr nodes.Manager 38 conf config.Config 39 queue datastore.ReplicationEventQueue 40 rs datastore.RepositoryStore 41 assignmentStore AssignmentStore 42 conns service.Connections 43 primaryGetter PrimaryGetter 44} 45 46// NewServer creates a new instance of a grpc InfoServiceServer 47func NewServer( 48 nodeMgr nodes.Manager, 49 conf config.Config, 50 queue datastore.ReplicationEventQueue, 51 rs datastore.RepositoryStore, 52 assignmentStore AssignmentStore, 53 conns service.Connections, 54 primaryGetter PrimaryGetter, 55) gitalypb.PraefectInfoServiceServer { 56 return &Server{ 57 nodeMgr: nodeMgr, 58 conf: conf, 59 queue: queue, 60 rs: rs, 61 assignmentStore: assignmentStore, 62 conns: conns, 63 primaryGetter: primaryGetter, 64 } 65} 66 67func (s *Server) SetAuthoritativeStorage(ctx context.Context, req *gitalypb.SetAuthoritativeStorageRequest) (*gitalypb.SetAuthoritativeStorageResponse, error) { 68 storages := s.conf.StorageNames()[req.VirtualStorage] 69 if storages == nil { 70 return nil, helper.ErrInvalidArgumentf("unknown virtual storage: %q", req.VirtualStorage) 71 } 72 73 foundStorage := false 74 for i := range storages { 75 if storages[i] == req.AuthoritativeStorage { 76 foundStorage = true 77 break 78 } 79 } 80 81 if !foundStorage { 82 return nil, helper.ErrInvalidArgumentf("unknown authoritative storage: %q", req.AuthoritativeStorage) 83 } 84 85 exists, err := s.rs.RepositoryExists(ctx, req.VirtualStorage, req.RelativePath) 86 if err != nil { 87 return nil, err 88 } else if !exists { 89 return nil, helper.ErrInvalidArgumentf("repository %q does not exist on virtual storage %q", req.RelativePath, req.VirtualStorage) 90 } 91 92 if err := s.rs.IncrementGeneration(ctx, req.VirtualStorage, req.RelativePath, req.AuthoritativeStorage, nil); err != nil { 93 return nil, helper.ErrInternal(err) 94 } 95 96 // Schedule replication jobs to other physical storages to get them consistent with the 97 // new authoritative repository. 98 for _, storage := range storages { 99 if storage == req.AuthoritativeStorage { 100 continue 101 } 102 103 if _, err := s.queue.Enqueue(ctx, datastore.ReplicationEvent{ 104 Job: datastore.ReplicationJob{ 105 Change: datastore.UpdateRepo, 106 VirtualStorage: req.VirtualStorage, 107 RelativePath: req.RelativePath, 108 SourceNodeStorage: req.AuthoritativeStorage, 109 TargetNodeStorage: storage, 110 }, 111 }); err != nil { 112 return nil, helper.ErrInternal(err) 113 } 114 } 115 116 return &gitalypb.SetAuthoritativeStorageResponse{}, nil 117} 118