diff options
author | Zeger-Jan van de Weg <git@zjvandeweg.nl> | 2021-07-14 12:08:04 +0300 |
---|---|---|
committer | Zeger-Jan van de Weg <git@zjvandeweg.nl> | 2021-07-14 12:08:04 +0300 |
commit | 47164700a1ea086c5e8ca0d02feefe4e68bf4f81 (patch) | |
tree | 3308274c2c475ca642524bc8f16a653b478dda46 | |
parent | 40511f7a14ded77c826809d054d740a66e1c106f (diff) | |
parent | e900df0947d188194f319b8afb9aa4fe857d357d (diff) |
Merge branch 'smh-dataloss-lazy-failovers' into 'master'
Support lazy failovers in `praefect dataloss`
See merge request gitlab-org/gitaly!3549
-rw-r--r-- | cmd/praefect/subcmd_dataloss.go | 56 | ||||
-rw-r--r-- | cmd/praefect/subcmd_dataloss_test.go | 253 | ||||
-rw-r--r-- | internal/praefect/datastore/repository_store.go | 75 | ||||
-rw-r--r-- | internal/praefect/datastore/repository_store_mock.go | 31 | ||||
-rw-r--r-- | internal/praefect/datastore/repository_store_test.go | 401 | ||||
-rw-r--r-- | internal/praefect/service/info/dataloss.go | 26 | ||||
-rw-r--r-- | proto/go/gitalypb/praefect.pb.go | 232 | ||||
-rw-r--r-- | proto/go/gitalypb/praefect_grpc.pb.go | 4 | ||||
-rw-r--r-- | proto/praefect.proto | 16 | ||||
-rw-r--r-- | ruby/proto/gitaly/praefect_pb.rb | 4 | ||||
-rw-r--r-- | ruby/proto/gitaly/praefect_services_pb.rb | 2 |
11 files changed, 586 insertions, 514 deletions
diff --git a/cmd/praefect/subcmd_dataloss.go b/cmd/praefect/subcmd_dataloss.go index 037edc886..06b493d71 100644 --- a/cmd/praefect/subcmd_dataloss.go +++ b/cmd/praefect/subcmd_dataloss.go @@ -21,9 +21,9 @@ func (err unexpectedPositionalArgsError) Error() string { } type datalossSubcommand struct { - output io.Writer - virtualStorage string - includePartiallyReplicated bool + output io.Writer + virtualStorage string + includePartiallyAvailable bool } func newDatalossSubcommand() *datalossSubcommand { @@ -33,12 +33,10 @@ func newDatalossSubcommand() *datalossSubcommand { func (cmd *datalossSubcommand) FlagSet() *flag.FlagSet { fs := flag.NewFlagSet("dataloss", flag.ContinueOnError) fs.StringVar(&cmd.virtualStorage, "virtual-storage", "", "virtual storage to check for data loss") - fs.BoolVar(&cmd.includePartiallyReplicated, "partially-replicated", false, strings.TrimSpace(` -Additionally include repositories which are fully up to date on the -primary but outdated on some secondaries. Such repositories are writable -and do not suffer from data loss. The data on the primary is not fully -replicated to all secondaries which leads to increased risk of data loss -following a failover.`)) + fs.BoolVar(&cmd.includePartiallyAvailable, "partially-unavailable", false, strings.TrimSpace(` +Additionally include repositories which are available but some assigned replicas +are unavailable. Such repositories are available but are not fully replicated. This +increases the change of data loss on primary failure`)) return fs } @@ -82,7 +80,7 @@ func (cmd *datalossSubcommand) Exec(flags *flag.FlagSet, cfg config.Config) erro for _, vs := range virtualStorages { resp, err := client.DatalossCheck(context.Background(), &gitalypb.DatalossCheckRequest{ VirtualStorage: vs, - IncludePartiallyReplicated: cmd.includePartiallyReplicated, + IncludePartiallyReplicated: cmd.includePartiallyAvailable, }) if err != nil { return fmt.Errorf("error checking: %v", err) @@ -90,23 +88,23 @@ func (cmd *datalossSubcommand) Exec(flags *flag.FlagSet, cfg config.Config) erro cmd.println(0, "Virtual storage: %s", vs) if len(resp.Repositories) == 0 { - msg := "All repositories are writable!" - if cmd.includePartiallyReplicated { - msg = "All repositories are up to date!" + msg := "All repositories are available!" + if cmd.includePartiallyAvailable { + msg = "All repositories are fully available on all assigned storages!" } cmd.println(1, msg) continue } - cmd.println(1, "Outdated repositories:") + cmd.println(1, "Repositories:") for _, repo := range resp.Repositories { - mode := "writable" - if repo.ReadOnly { - mode = "read-only" + unavailable := "" + if repo.Unavailable { + unavailable = " (unavailable)" } - cmd.println(2, "%s (%s):", repo.RelativePath, mode) + cmd.println(2, "%s%s:", repo.RelativePath, unavailable) primary := repo.Primary if primary == "" { @@ -120,7 +118,11 @@ func (cmd *datalossSubcommand) Exec(flags *flag.FlagSet, cfg config.Config) erro continue } - cmd.println(4, "%s%s", storage.Name, assignedMessage(storage.Assigned)) + cmd.println(4, "%s%s%s", + storage.Name, + assignedMessage(storage.Assigned), + unhealthyMessage(storage.Healthy), + ) } cmd.println(3, "Outdated Storages:") @@ -134,7 +136,13 @@ func (cmd *datalossSubcommand) Exec(flags *flag.FlagSet, cfg config.Config) erro plural = "s" } - cmd.println(4, "%s is behind by %d change%s or less%s", storage.Name, storage.BehindBy, plural, assignedMessage(storage.Assigned)) + cmd.println(4, "%s is behind by %d change%s or less%s%s", + storage.Name, + storage.BehindBy, + plural, + assignedMessage(storage.Assigned), + unhealthyMessage(storage.Healthy), + ) } } } @@ -142,6 +150,14 @@ func (cmd *datalossSubcommand) Exec(flags *flag.FlagSet, cfg config.Config) erro return nil } +func unhealthyMessage(healthy bool) string { + if healthy { + return "" + } + + return ", unhealthy" +} + func assignedMessage(assigned bool) string { assignedMsg := "" if assigned { diff --git a/cmd/praefect/subcmd_dataloss_test.go b/cmd/praefect/subcmd_dataloss_test.go index e52cf0f42..bfe7c03b3 100644 --- a/cmd/praefect/subcmd_dataloss_test.go +++ b/cmd/praefect/subcmd_dataloss_test.go @@ -4,7 +4,6 @@ package main import ( "bytes" - "fmt" "testing" "github.com/stretchr/testify/require" @@ -28,63 +27,45 @@ func registerPraefectInfoServer(impl gitalypb.PraefectInfoServiceServer) svcRegi } func TestDatalossSubcommand(t *testing.T) { - for _, scope := range []struct { - desc string - electionStrategy config.ElectionStrategy - primaries map[string]string - }{ - { - desc: "sql elector", - electionStrategy: config.ElectionStrategySQL, - primaries: map[string]string{ - "repository-1": "gitaly-1", - "repository-2": "gitaly-1", + cfg := config.Config{ + VirtualStorages: []*config.VirtualStorage{ + { + Name: "virtual-storage-1", + Nodes: []*config.Node{ + {Storage: "gitaly-1"}, + {Storage: "gitaly-2"}, + {Storage: "gitaly-3"}, + }, }, - }, - { - desc: "per_repository elector", - electionStrategy: config.ElectionStrategyPerRepository, - primaries: map[string]string{ - "repository-1": "gitaly-1", - "repository-2": "gitaly-3", + { + Name: "virtual-storage-2", + Nodes: []*config.Node{ + {Storage: "gitaly-4"}, + }, }, }, - } { - t.Run(scope.desc, func(t *testing.T) { - cfg := config.Config{ - Failover: config.Failover{ElectionStrategy: scope.electionStrategy}, - VirtualStorages: []*config.VirtualStorage{ - { - Name: "virtual-storage-1", - Nodes: []*config.Node{ - {Storage: "gitaly-1"}, - {Storage: "gitaly-2"}, - {Storage: "gitaly-3"}, - }, - }, - { - Name: "virtual-storage-2", - Nodes: []*config.Node{ - {Storage: "gitaly-4"}, - }, - }, - }, - } + } + + tx, err := getDB(t).Begin() + require.NoError(t, err) + defer tx.Rollback() - db := getDB(t) - gs := datastore.NewPostgresRepositoryStore(db, cfg.StorageNames()) + ctx, cancel := testhelper.Context() + defer cancel() - ctx, cancel := testhelper.Context() - defer cancel() + testhelper.SetHealthyNodes(t, ctx, tx, map[string]map[string][]string{"praefect-0": { + "virtual-storage-1": {"gitaly-1", "gitaly-3"}, + }}) + gs := datastore.NewPostgresRepositoryStore(tx, cfg.StorageNames()) - for _, q := range []string{ - ` + for _, q := range []string{ + ` INSERT INTO repositories (virtual_storage, relative_path, "primary") VALUES ('virtual-storage-1', 'repository-1', 'gitaly-1'), ('virtual-storage-1', 'repository-2', 'gitaly-3') `, - ` + ` INSERT INTO repository_assignments (virtual_storage, relative_path, storage) VALUES ('virtual-storage-1', 'repository-1', 'gitaly-1'), @@ -92,128 +73,122 @@ func TestDatalossSubcommand(t *testing.T) { ('virtual-storage-1', 'repository-2', 'gitaly-1'), ('virtual-storage-1', 'repository-2', 'gitaly-3') `, - ` - INSERT INTO shard_primaries (shard_name, node_name, elected_by_praefect, elected_at) - VALUES ('virtual-storage-1', 'gitaly-1', 'ignored', now()) - `, - } { - _, err := db.ExecContext(ctx, q) - require.NoError(t, err) - } + } { + _, err := tx.ExecContext(ctx, q) + require.NoError(t, err) + } - require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-1", "gitaly-1", 1)) - require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-1", "gitaly-2", 0)) - require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-1", "gitaly-3", 0)) + require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-1", "gitaly-1", 1)) + require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-1", "gitaly-2", 0)) + require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-1", "gitaly-3", 0)) - require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-2", "gitaly-2", 1)) - require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-2", "gitaly-3", 0)) + require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-2", "gitaly-2", 1)) + require.NoError(t, gs.SetGeneration(ctx, "virtual-storage-1", "repository-2", "gitaly-3", 0)) - ln, clean := listenAndServe(t, []svcRegistrar{ - registerPraefectInfoServer(info.NewServer(nil, cfg, nil, gs, nil, nil, nil))}) - defer clean() - for _, tc := range []struct { - desc string - args []string - virtualStorages []*config.VirtualStorage - output string - error error - }{ - { - desc: "positional arguments", - args: []string{"-virtual-storage=virtual-storage-1", "positional-arg"}, - error: unexpectedPositionalArgsError{Command: "dataloss"}, - }, - { - desc: "data loss with read-only repositories", - args: []string{"-virtual-storage=virtual-storage-1"}, - output: fmt.Sprintf(`Virtual storage: virtual-storage-1 - Outdated repositories: - repository-2 (read-only): - Primary: %s + ln, clean := listenAndServe(t, []svcRegistrar{ + registerPraefectInfoServer(info.NewServer(nil, cfg, nil, gs, nil, nil, nil))}) + defer clean() + for _, tc := range []struct { + desc string + args []string + virtualStorages []*config.VirtualStorage + output string + error error + }{ + { + desc: "positional arguments", + args: []string{"-virtual-storage=virtual-storage-1", "positional-arg"}, + error: unexpectedPositionalArgsError{Command: "dataloss"}, + }, + { + desc: "data loss with unavailable repositories", + args: []string{"-virtual-storage=virtual-storage-1"}, + output: `Virtual storage: virtual-storage-1 + Repositories: + repository-2 (unavailable): + Primary: gitaly-3 In-Sync Storages: - gitaly-2 + gitaly-2, unhealthy Outdated Storages: gitaly-1 is behind by 2 changes or less, assigned host gitaly-3 is behind by 1 change or less, assigned host -`, scope.primaries["repository-2"]), - }, - { - desc: "data loss with partially replicated repositories", - args: []string{"-virtual-storage=virtual-storage-1", "-partially-replicated"}, - output: fmt.Sprintf(`Virtual storage: virtual-storage-1 - Outdated repositories: - repository-1 (writable): - Primary: %s +`, + }, + { + desc: "data loss with partially unavailable repositories", + args: []string{"-virtual-storage=virtual-storage-1", "-partially-unavailable"}, + output: `Virtual storage: virtual-storage-1 + Repositories: + repository-1: + Primary: gitaly-1 In-Sync Storages: gitaly-1, assigned host Outdated Storages: - gitaly-2 is behind by 1 change or less, assigned host + gitaly-2 is behind by 1 change or less, assigned host, unhealthy gitaly-3 is behind by 1 change or less - repository-2 (read-only): - Primary: %s + repository-2 (unavailable): + Primary: gitaly-3 In-Sync Storages: - gitaly-2 + gitaly-2, unhealthy Outdated Storages: gitaly-1 is behind by 2 changes or less, assigned host gitaly-3 is behind by 1 change or less, assigned host -`, scope.primaries["repository-1"], scope.primaries["repository-2"]), - }, - { - desc: "multiple virtual storages with read-only repositories", - virtualStorages: []*config.VirtualStorage{{Name: "virtual-storage-2"}, {Name: "virtual-storage-1"}}, - output: fmt.Sprintf(`Virtual storage: virtual-storage-1 - Outdated repositories: - repository-2 (read-only): - Primary: %s +`, + }, + { + desc: "multiple virtual storages with unavailable repositories", + virtualStorages: []*config.VirtualStorage{{Name: "virtual-storage-2"}, {Name: "virtual-storage-1"}}, + output: `Virtual storage: virtual-storage-1 + Repositories: + repository-2 (unavailable): + Primary: gitaly-3 In-Sync Storages: - gitaly-2 + gitaly-2, unhealthy Outdated Storages: gitaly-1 is behind by 2 changes or less, assigned host gitaly-3 is behind by 1 change or less, assigned host Virtual storage: virtual-storage-2 - All repositories are writable! -`, scope.primaries["repository-2"]), - }, - { - desc: "multiple virtual storages with partially replicated repositories", - args: []string{"-partially-replicated"}, - virtualStorages: []*config.VirtualStorage{{Name: "virtual-storage-2"}, {Name: "virtual-storage-1"}}, - output: fmt.Sprintf(`Virtual storage: virtual-storage-1 - Outdated repositories: - repository-1 (writable): - Primary: %s + All repositories are available! +`, + }, + { + desc: "multiple virtual storages with partially unavailable repositories", + args: []string{"-partially-unavailable"}, + virtualStorages: []*config.VirtualStorage{{Name: "virtual-storage-2"}, {Name: "virtual-storage-1"}}, + output: `Virtual storage: virtual-storage-1 + Repositories: + repository-1: + Primary: gitaly-1 In-Sync Storages: gitaly-1, assigned host Outdated Storages: - gitaly-2 is behind by 1 change or less, assigned host + gitaly-2 is behind by 1 change or less, assigned host, unhealthy gitaly-3 is behind by 1 change or less - repository-2 (read-only): - Primary: %s + repository-2 (unavailable): + Primary: gitaly-3 In-Sync Storages: - gitaly-2 + gitaly-2, unhealthy Outdated Storages: gitaly-1 is behind by 2 changes or less, assigned host gitaly-3 is behind by 1 change or less, assigned host Virtual storage: virtual-storage-2 - All repositories are up to date! -`, scope.primaries["repository-1"], scope.primaries["repository-2"]), - }, - } { - t.Run(tc.desc, func(t *testing.T) { - cmd := newDatalossSubcommand() - output := &bytes.Buffer{} - cmd.output = output + All repositories are fully available on all assigned storages! +`, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + cmd := newDatalossSubcommand() + output := &bytes.Buffer{} + cmd.output = output - fs := cmd.FlagSet() - require.NoError(t, fs.Parse(tc.args)) - err := cmd.Exec(fs, config.Config{ - VirtualStorages: tc.virtualStorages, - SocketPath: ln.Addr().String(), - }) - require.Equal(t, tc.error, err, err) - require.Equal(t, tc.output, output.String()) - }) - } + fs := cmd.FlagSet() + require.NoError(t, fs.Parse(tc.args)) + err := cmd.Exec(fs, config.Config{ + VirtualStorages: tc.virtualStorages, + SocketPath: ln.Addr().String(), + }) + require.Equal(t, tc.error, err, err) + require.Equal(t, tc.output, output.String()) }) } } diff --git a/internal/praefect/datastore/repository_store.go b/internal/praefect/datastore/repository_store.go index 7a1702b6d..278f4e3ea 100644 --- a/internal/praefect/datastore/repository_store.go +++ b/internal/praefect/datastore/repository_store.go @@ -116,10 +116,9 @@ type RepositoryStore interface { ConsistentStoragesGetter // RepositoryExists returns whether the repository exists on a virtual storage. RepositoryExists(ctx context.Context, virtualStorage, relativePath string) (bool, error) - // GetPartiallyReplicatedRepositories returns information on repositories which have an outdated copy on an assigned storage. - // By default, repository specific primaries are returned in the results. If useVirtualStoragePrimaries is set, virtual storage's - // primary is returned instead for each repository. - GetPartiallyReplicatedRepositories(ctx context.Context, virtualStorage string, virtualStoragePrimaries bool) ([]OutdatedRepository, error) + // GetPartiallyAvailableRepositories returns information on repositories which have assigned replicas which + // are not able to serve requests at the moment. + GetPartiallyAvailableRepositories(ctx context.Context, virtualStorage string) ([]PartiallyAvailableRepository, error) // DeleteInvalidRepository is a method for deleting records of invalid repositories. It deletes a storage's // record of the invalid repository. If the storage was the only storage with the repository, the repository's // record on the virtual storage is also deleted. @@ -519,36 +518,45 @@ AND NOT EXISTS ( return err } -// OutdatedRepositoryStorageDetails represents a storage that contains or should contain a +// StorageDetails represents a storage that contains or should contain a // copy of the repository. -type OutdatedRepositoryStorageDetails struct { +type StorageDetails struct { // Name of the storage as configured. Name string // BehindBy indicates how many generations the storage's copy of the repository is missing at maximum. BehindBy int // Assigned indicates whether the storage is an assigned host of the repository. Assigned bool + // Healthy indicates whether the replica is considered healthy by the consensus of Praefect nodes. + Healthy bool + // ValidPrimary indicates whether the replica is ready to serve as the primary if necessary. + ValidPrimary bool } -// OutdatedRepository is a repository with one or more outdated assigned storages. -type OutdatedRepository struct { +// PartiallyAvailableRepository is a repository with one or more assigned replicas which are not +// able to serve requests at the moment. +type PartiallyAvailableRepository struct { // RelativePath is the relative path of the repository. RelativePath string // Primary is the current primary of this repository. Primary string // Storages contains information of the repository on each storage that contains the repository // or does not contain the repository but is assigned to host it. - Storages []OutdatedRepositoryStorageDetails + Storages []StorageDetails } -func (rs *PostgresRepositoryStore) GetPartiallyReplicatedRepositories(ctx context.Context, virtualStorage string, useVirtualStoragePrimaries bool) ([]OutdatedRepository, error) { +// GetPartiallyAvailableRepositories returns information on repositories which have assigned replicas which +// are not able to serve requests at the moment. +func (rs *PostgresRepositoryStore) GetPartiallyAvailableRepositories(ctx context.Context, virtualStorage string) ([]PartiallyAvailableRepository, error) { configuredStorages, ok := rs.storages[virtualStorage] if !ok { return nil, fmt.Errorf("unknown virtual storage: %q", virtualStorage) } - // The query below gets the generations and assignments of every repository - // which has one or more outdated assigned nodes. It works as follows: + // The query below gets the status of every repository which has one or more assigned replicas that + // are not able to serve requests at the moment. The status includes how many changes a replica is behind, + // whether the replica is assigned host or not, whether the replica is healthy and whether the replica is + // considered a valid primary candidate. It works as follows: // // 1. First we get all the storages which contain the repository from `storage_repositories`. We // list every copy of the repository as the latest generation could exist on an unassigned @@ -569,13 +577,17 @@ func (rs *PostgresRepositoryStore) GetPartiallyReplicatedRepositories(ctx contex // and there can't be any assignments for deleted repositories, this is still needed as long as the // fallback behavior of no assignments is in place. // - // 4. Finally we aggregate each repository's information in to a single row with a JSON object containing + // 4. We join the `healthy_storages` view to return the storages current health. + // + // 5. We join the `valid_primaries` view to return whether the storage is ready to act as a primary in case + // of a failover. + // + // 6. Finally we aggregate each repository's information in to a single row with a JSON object containing // the information. This allows us to group the output already in the query and makes scanning easier - // We filter out groups which do not have an outdated assigned storage as the replication factor on those + // We filter out groups which do not have an assigned storage as the replication factor on those // is reached. Status of unassigned storages does not matter as long as they don't contain a later generation // than the assigned ones. // - // If virtual storage scoped primaries are used, the primary is instead selected from the `shard_primaries` table. rows, err := rs.db.QueryContext(ctx, ` SELECT json_build_object ( @@ -585,20 +597,21 @@ SELECT json_build_object( 'Name', storage, 'BehindBy', behind_by, - 'Assigned', assigned + 'Assigned', assigned, + 'Healthy', healthy, + 'ValidPrimary', valid_primary ) ) ) FROM ( SELECT relative_path, - CASE WHEN $3 - THEN shard_primaries.node_name - ELSE repositories."primary" - END AS "primary", + repositories.primary, storage, - max(storage_repositories.generation) OVER (PARTITION BY virtual_storage, relative_path) - COALESCE(storage_repositories.generation, -1) AS behind_by, - repository_assignments.storage IS NOT NULL AS assigned + repository_generations.generation - COALESCE(storage_repositories.generation, -1) AS behind_by, + repository_assignments.storage IS NOT NULL AS assigned, + healthy_storages.storage IS NOT NULL AS healthy, + valid_primaries.storage IS NOT NULL AS valid_primary FROM storage_repositories FULL JOIN ( SELECT virtual_storage, relative_path, storage @@ -613,33 +626,35 @@ FROM ( ) ) AS repository_assignments USING (virtual_storage, relative_path, storage) JOIN repositories USING (virtual_storage, relative_path) - LEFT JOIN shard_primaries ON $3 AND shard_name = virtual_storage AND NOT demoted + JOIN repository_generations USING (virtual_storage, relative_path) + LEFT JOIN healthy_storages USING (virtual_storage, storage) + LEFT JOIN valid_primaries USING (virtual_storage, relative_path, storage) WHERE virtual_storage = $1 ORDER BY relative_path, "primary", storage ) AS outdated_repositories GROUP BY relative_path, "primary" -HAVING max(behind_by) FILTER(WHERE assigned) > 0 +HAVING bool_or(NOT valid_primary) FILTER(WHERE assigned) ORDER BY relative_path, "primary" - `, virtualStorage, pq.StringArray(configuredStorages), useVirtualStoragePrimaries) + `, virtualStorage, pq.StringArray(configuredStorages)) if err != nil { return nil, fmt.Errorf("query: %w", err) } defer rows.Close() - var outdatedRepos []OutdatedRepository + var repos []PartiallyAvailableRepository for rows.Next() { var repositoryJSON string if err := rows.Scan(&repositoryJSON); err != nil { return nil, fmt.Errorf("scan: %w", err) } - var outdatedRepo OutdatedRepository - if err := json.NewDecoder(strings.NewReader(repositoryJSON)).Decode(&outdatedRepo); err != nil { + var repo PartiallyAvailableRepository + if err := json.NewDecoder(strings.NewReader(repositoryJSON)).Decode(&repo); err != nil { return nil, fmt.Errorf("decode json: %w", err) } - outdatedRepos = append(outdatedRepos, outdatedRepo) + repos = append(repos, repo) } - return outdatedRepos, rows.Err() + return repos, rows.Err() } diff --git a/internal/praefect/datastore/repository_store_mock.go b/internal/praefect/datastore/repository_store_mock.go index 3c5b5f81c..876dcec73 100644 --- a/internal/praefect/datastore/repository_store_mock.go +++ b/internal/praefect/datastore/repository_store_mock.go @@ -5,18 +5,18 @@ import "context" // MockRepositoryStore allows for mocking a RepositoryStore by parametrizing its behavior. All methods // default to what could be considered success if not set. type MockRepositoryStore struct { - GetGenerationFunc func(ctx context.Context, virtualStorage, relativePath, storage string) (int, error) - IncrementGenerationFunc func(ctx context.Context, virtualStorage, relativePath, primary string, secondaries []string) error - GetReplicatedGenerationFunc func(ctx context.Context, virtualStorage, relativePath, source, target string) (int, error) - SetGenerationFunc func(ctx context.Context, virtualStorage, relativePath, storage string, generation int) error - CreateRepositoryFunc func(ctx context.Context, virtualStorage, relativePath, primary string, updatedSecondaries, outdatedSecondaries []string, storePrimary, storeAssignments bool) error - DeleteRepositoryFunc func(ctx context.Context, virtualStorage, relativePath string, storages []string) error - DeleteReplicaFunc func(ctx context.Context, virtualStorage, relativePath, storage string) error - RenameRepositoryFunc func(ctx context.Context, virtualStorage, relativePath, storage, newRelativePath string) error - GetConsistentStoragesFunc func(ctx context.Context, virtualStorage, relativePath string) (map[string]struct{}, error) - GetPartiallyReplicatedRepositoriesFunc func(ctx context.Context, virtualStorage string, virtualStorageScopedPrimaries bool) ([]OutdatedRepository, error) - DeleteInvalidRepositoryFunc func(ctx context.Context, virtualStorage, relativePath, storage string) error - RepositoryExistsFunc func(ctx context.Context, virtualStorage, relativePath string) (bool, error) + GetGenerationFunc func(ctx context.Context, virtualStorage, relativePath, storage string) (int, error) + IncrementGenerationFunc func(ctx context.Context, virtualStorage, relativePath, primary string, secondaries []string) error + GetReplicatedGenerationFunc func(ctx context.Context, virtualStorage, relativePath, source, target string) (int, error) + SetGenerationFunc func(ctx context.Context, virtualStorage, relativePath, storage string, generation int) error + CreateRepositoryFunc func(ctx context.Context, virtualStorage, relativePath, primary string, updatedSecondaries, outdatedSecondaries []string, storePrimary, storeAssignments bool) error + DeleteRepositoryFunc func(ctx context.Context, virtualStorage, relativePath string, storages []string) error + DeleteReplicaFunc func(ctx context.Context, virtualStorage, relativePath, storage string) error + RenameRepositoryFunc func(ctx context.Context, virtualStorage, relativePath, storage, newRelativePath string) error + GetConsistentStoragesFunc func(ctx context.Context, virtualStorage, relativePath string) (map[string]struct{}, error) + GetPartiallyAvailableRepositoriesFunc func(ctx context.Context, virtualStorage string) ([]PartiallyAvailableRepository, error) + DeleteInvalidRepositoryFunc func(ctx context.Context, virtualStorage, relativePath, storage string) error + RepositoryExistsFunc func(ctx context.Context, virtualStorage, relativePath string) (bool, error) } func (m MockRepositoryStore) GetGeneration(ctx context.Context, virtualStorage, relativePath, storage string) (int, error) { @@ -95,12 +95,13 @@ func (m MockRepositoryStore) GetConsistentStorages(ctx context.Context, virtualS return m.GetConsistentStoragesFunc(ctx, virtualStorage, relativePath) } -func (m MockRepositoryStore) GetPartiallyReplicatedRepositories(ctx context.Context, virtualStorage string, virtualStorageScopedPrimaries bool) ([]OutdatedRepository, error) { - if m.GetPartiallyReplicatedRepositoriesFunc == nil { +// GetPartiallyAvailableRepositories returns the result of GetPartiallyAvailableRepositories or nil if it is unset. +func (m MockRepositoryStore) GetPartiallyAvailableRepositories(ctx context.Context, virtualStorage string) ([]PartiallyAvailableRepository, error) { + if m.GetPartiallyAvailableRepositoriesFunc == nil { return nil, nil } - return m.GetPartiallyReplicatedRepositoriesFunc(ctx, virtualStorage, virtualStorageScopedPrimaries) + return m.GetPartiallyAvailableRepositoriesFunc(ctx, virtualStorage) } func (m MockRepositoryStore) DeleteInvalidRepository(ctx context.Context, virtualStorage, relativePath, storage string) error { diff --git a/internal/praefect/datastore/repository_store_test.go b/internal/praefect/datastore/repository_store_test.go index 57e61dac0..ad5058aca 100644 --- a/internal/praefect/datastore/repository_store_test.go +++ b/internal/praefect/datastore/repository_store_test.go @@ -799,208 +799,249 @@ func testRepositoryStore(t *testing.T, newStore repositoryStoreFactory) { }) } -func TestPostgresRepositoryStore_GetPartiallyReplicatedRepositories(t *testing.T) { - for _, scope := range []struct { - desc string - useVirtualStoragePrimaries bool - primary string +func TestPostgresRepositoryStore_GetPartiallyAvailableRepositories(t *testing.T) { + for _, tc := range []struct { + desc string + nonExistentRepository bool + unhealthyStorages map[string]struct{} + existingGenerations map[string]int + existingAssignments []string + storageDetails []StorageDetails }{ - {desc: "virtual storage primaries", useVirtualStoragePrimaries: true, primary: "virtual-storage-primary"}, - {desc: "repository primaries", useVirtualStoragePrimaries: false, primary: "repository-primary"}, + { + desc: "all up to date without assignments", + existingGenerations: map[string]int{"primary": 0, "secondary-1": 0}, + }, + { + desc: "unconfigured node outdated without assignments", + existingGenerations: map[string]int{"primary": 1, "secondary-1": 1, "unconfigured": 0}, + }, + { + desc: "unconfigured node contains the latest", + existingGenerations: map[string]int{"primary": 0, "secondary-1": 0, "unconfigured": 1}, + storageDetails: []StorageDetails{ + {Name: "primary", BehindBy: 1, Assigned: true, Healthy: true}, + {Name: "secondary-1", BehindBy: 1, Assigned: true, Healthy: true}, + {Name: "unconfigured", BehindBy: 0, Assigned: false}, + }, + }, + { + desc: "node has no repository without assignments", + existingGenerations: map[string]int{"primary": 0}, + storageDetails: []StorageDetails{ + {Name: "primary", BehindBy: 0, Assigned: true, Healthy: true, ValidPrimary: true}, + {Name: "secondary-1", BehindBy: 1, Assigned: true, Healthy: true}, + }, + }, + { + desc: "node has outdated repository without assignments", + existingGenerations: map[string]int{"primary": 1, "secondary-1": 0}, + storageDetails: []StorageDetails{ + {Name: "primary", BehindBy: 0, Assigned: true, Healthy: true, ValidPrimary: true}, + {Name: "secondary-1", BehindBy: 1, Assigned: true, Healthy: true}, + }, + }, + { + desc: "node with no repository heavily outdated", + existingGenerations: map[string]int{"primary": 10}, + storageDetails: []StorageDetails{ + {Name: "primary", BehindBy: 0, Assigned: true, Healthy: true, ValidPrimary: true}, + {Name: "secondary-1", BehindBy: 11, Assigned: true, Healthy: true}, + }, + }, + { + desc: "node with a heavily outdated repository", + existingGenerations: map[string]int{"primary": 10, "secondary-1": 0}, + storageDetails: []StorageDetails{ + {Name: "primary", BehindBy: 0, Assigned: true, Healthy: true, ValidPrimary: true}, + {Name: "secondary-1", BehindBy: 10, Assigned: true, Healthy: true}, + }, + }, + { + desc: "outdated nodes ignored when repository should not exist", + nonExistentRepository: true, + existingGenerations: map[string]int{"primary": 1, "secondary-1": 0}, + }, + { + desc: "unassigned node has no repository", + existingAssignments: []string{"primary"}, + existingGenerations: map[string]int{"primary": 0}, + }, + { + desc: "unassigned node has an outdated repository", + existingAssignments: []string{"primary"}, + existingGenerations: map[string]int{"primary": 1, "secondary-1": 0}, + }, + { + desc: "assigned node has no repository", + existingAssignments: []string{"primary", "secondary-1"}, + existingGenerations: map[string]int{"primary": 0}, + storageDetails: []StorageDetails{ + {Name: "primary", BehindBy: 0, Assigned: true, Healthy: true, ValidPrimary: true}, + {Name: "secondary-1", BehindBy: 1, Assigned: true, Healthy: true}, + }, + }, + { + desc: "assigned node has outdated repository", + existingAssignments: []string{"primary", "secondary-1"}, + existingGenerations: map[string]int{"primary": 1, "secondary-1": 0}, + storageDetails: []StorageDetails{ + {Name: "primary", BehindBy: 0, Assigned: true, Healthy: true, ValidPrimary: true}, + {Name: "secondary-1", BehindBy: 1, Assigned: true, Healthy: true}, + }, + }, + { + desc: "unassigned node contains the latest repository", + existingAssignments: []string{"primary"}, + existingGenerations: map[string]int{"primary": 0, "secondary-1": 1}, + storageDetails: []StorageDetails{ + {Name: "primary", BehindBy: 1, Assigned: true, Healthy: true}, + {Name: "secondary-1", BehindBy: 0, Assigned: false, Healthy: true, ValidPrimary: true}, + }, + }, + { + desc: "unassigned node contains the only repository", + existingAssignments: []string{"primary"}, + existingGenerations: map[string]int{"secondary-1": 0}, + storageDetails: []StorageDetails{ + {Name: "primary", BehindBy: 1, Assigned: true, Healthy: true}, + {Name: "secondary-1", BehindBy: 0, Assigned: false, Healthy: true, ValidPrimary: true}, + }, + }, + { + desc: "unassigned unconfigured node contains the only repository", + existingAssignments: []string{"primary"}, + existingGenerations: map[string]int{"unconfigured": 0}, + storageDetails: []StorageDetails{ + {Name: "primary", BehindBy: 1, Assigned: true, Healthy: true}, + {Name: "unconfigured", BehindBy: 0, Assigned: false}, + }, + }, + { + desc: "assigned unconfigured node has no repository", + existingAssignments: []string{"primary", "unconfigured"}, + existingGenerations: map[string]int{"primary": 1}, + }, + { + desc: "assigned unconfigured node is outdated", + existingAssignments: []string{"primary", "unconfigured"}, + existingGenerations: map[string]int{"primary": 1, "unconfigured": 0}, + }, + { + desc: "unconfigured node is the only assigned node", + existingAssignments: []string{"unconfigured"}, + existingGenerations: map[string]int{"unconfigured": 0}, + storageDetails: []StorageDetails{ + {Name: "primary", BehindBy: 1, Assigned: true, Healthy: true}, + {Name: "secondary-1", BehindBy: 1, Assigned: true, Healthy: true}, + {Name: "unconfigured", BehindBy: 0, Assigned: false}, + }, + }, + { + desc: "repository is fully replicated but unavailable", + unhealthyStorages: map[string]struct{}{"primary": {}, "secondary-1": {}}, + existingAssignments: []string{"primary", "secondary-1"}, + existingGenerations: map[string]int{"primary": 0, "secondary-1": 0}, + storageDetails: []StorageDetails{ + {Name: "primary", Assigned: true}, + {Name: "secondary-1", Assigned: true}, + }, + }, + { + desc: "assigned replicas unavailable but a valid unassigned primary candidate", + unhealthyStorages: map[string]struct{}{"primary": {}}, + existingAssignments: []string{"primary"}, + existingGenerations: map[string]int{"primary": 0, "secondary-1": 0}, + storageDetails: []StorageDetails{ + {Name: "primary", Assigned: true}, + {Name: "secondary-1", Healthy: true, ValidPrimary: true}, + }, + }, + { + desc: "assigned replicas available but unassigned replica unavailable", + unhealthyStorages: map[string]struct{}{"secondary-1": {}}, + existingAssignments: []string{"primary"}, + existingGenerations: map[string]int{"primary": 0, "secondary-1": 0}, + }, + { + desc: "one assigned replica unavailable", + unhealthyStorages: map[string]struct{}{"secondary-1": {}}, + existingAssignments: []string{"primary", "secondary-1"}, + existingGenerations: map[string]int{"primary": 0, "secondary-1": 0}, + storageDetails: []StorageDetails{ + {Name: "primary", Assigned: true, Healthy: true, ValidPrimary: true}, + {Name: "secondary-1", Assigned: true}, + }, + }, } { - t.Run(scope.desc, func(t *testing.T) { - for _, tc := range []struct { - desc string - nonExistentRepository bool - existingGenerations map[string]int - existingAssignments []string - storageDetails []OutdatedRepositoryStorageDetails - }{ - { - desc: "all up to date without assignments", - existingGenerations: map[string]int{"primary": 0, "secondary-1": 0}, - }, - { - desc: "unconfigured node outdated without assignments", - existingGenerations: map[string]int{"primary": 1, "secondary-1": 1, "unconfigured": 0}, - }, - { - desc: "unconfigured node contains the latest", - existingGenerations: map[string]int{"primary": 0, "secondary-1": 0, "unconfigured": 1}, - storageDetails: []OutdatedRepositoryStorageDetails{ - {Name: "primary", BehindBy: 1, Assigned: true}, - {Name: "secondary-1", BehindBy: 1, Assigned: true}, - {Name: "unconfigured", BehindBy: 0, Assigned: false}, - }, - }, - { - desc: "node has no repository without assignments", - existingGenerations: map[string]int{"primary": 0}, - storageDetails: []OutdatedRepositoryStorageDetails{ - {Name: "primary", BehindBy: 0, Assigned: true}, - {Name: "secondary-1", BehindBy: 1, Assigned: true}, - }, - }, - { - desc: "node has outdated repository without assignments", - existingGenerations: map[string]int{"primary": 1, "secondary-1": 0}, - storageDetails: []OutdatedRepositoryStorageDetails{ - {Name: "primary", BehindBy: 0, Assigned: true}, - {Name: "secondary-1", BehindBy: 1, Assigned: true}, - }, - }, - { - desc: "node with no repository heavily outdated", - existingGenerations: map[string]int{"primary": 10}, - storageDetails: []OutdatedRepositoryStorageDetails{ - {Name: "primary", BehindBy: 0, Assigned: true}, - {Name: "secondary-1", BehindBy: 11, Assigned: true}, - }, - }, - { - desc: "node with a heavily outdated repository", - existingGenerations: map[string]int{"primary": 10, "secondary-1": 0}, - storageDetails: []OutdatedRepositoryStorageDetails{ - {Name: "primary", BehindBy: 0, Assigned: true}, - {Name: "secondary-1", BehindBy: 10, Assigned: true}, - }, - }, - { - desc: "outdated nodes ignored when repository should not exist", - nonExistentRepository: true, - existingGenerations: map[string]int{"primary": 1, "secondary-1": 0}, - }, - { - desc: "unassigned node has no repository", - existingAssignments: []string{"primary"}, - existingGenerations: map[string]int{"primary": 0}, - }, - { - desc: "unassigned node has an outdated repository", - existingAssignments: []string{"primary"}, - existingGenerations: map[string]int{"primary": 1, "secondary-1": 0}, - }, - { - desc: "assigned node has no repository", - existingAssignments: []string{"primary", "secondary-1"}, - existingGenerations: map[string]int{"primary": 0}, - storageDetails: []OutdatedRepositoryStorageDetails{ - {Name: "primary", BehindBy: 0, Assigned: true}, - {Name: "secondary-1", BehindBy: 1, Assigned: true}, - }, - }, - { - desc: "assigned node has outdated repository", - existingAssignments: []string{"primary", "secondary-1"}, - existingGenerations: map[string]int{"primary": 1, "secondary-1": 0}, - storageDetails: []OutdatedRepositoryStorageDetails{ - {Name: "primary", BehindBy: 0, Assigned: true}, - {Name: "secondary-1", BehindBy: 1, Assigned: true}, - }, - }, - { - desc: "unassigned node contains the latest repository", - existingAssignments: []string{"primary"}, - existingGenerations: map[string]int{"primary": 0, "secondary-1": 1}, - storageDetails: []OutdatedRepositoryStorageDetails{ - {Name: "primary", BehindBy: 1, Assigned: true}, - {Name: "secondary-1", BehindBy: 0, Assigned: false}, - }, - }, - { - desc: "unassigned node contains the only repository", - existingAssignments: []string{"primary"}, - existingGenerations: map[string]int{"secondary-1": 0}, - storageDetails: []OutdatedRepositoryStorageDetails{ - {Name: "primary", BehindBy: 1, Assigned: true}, - {Name: "secondary-1", BehindBy: 0, Assigned: false}, - }, - }, - { - desc: "unassigned unconfigured node contains the only repository", - existingAssignments: []string{"primary"}, - existingGenerations: map[string]int{"unconfigured": 0}, - storageDetails: []OutdatedRepositoryStorageDetails{ - {Name: "primary", BehindBy: 1, Assigned: true}, - {Name: "unconfigured", BehindBy: 0, Assigned: false}, - }, - }, - { - desc: "assigned unconfigured node has no repository", - existingAssignments: []string{"primary", "unconfigured"}, - existingGenerations: map[string]int{"primary": 1}, - }, - { - desc: "assigned unconfigured node is outdated", - existingAssignments: []string{"primary", "unconfigured"}, - existingGenerations: map[string]int{"primary": 1, "unconfigured": 0}, - }, - { - desc: "unconfigured node is the only assigned node", - existingAssignments: []string{"unconfigured"}, - existingGenerations: map[string]int{"unconfigured": 0}, - storageDetails: []OutdatedRepositoryStorageDetails{ - {Name: "primary", BehindBy: 1, Assigned: true}, - {Name: "secondary-1", BehindBy: 1, Assigned: true}, - {Name: "unconfigured", BehindBy: 0, Assigned: false}, - }, - }, - } { - t.Run(tc.desc, func(t *testing.T) { - ctx, cancel := testhelper.Context() - defer cancel() + t.Run(tc.desc, func(t *testing.T) { + ctx, cancel := testhelper.Context() + defer cancel() + + tx, err := getDB(t).Begin() + require.NoError(t, err) + defer tx.Rollback() + + configuredStorages := map[string][]string{"virtual-storage": {"primary", "secondary-1"}} + + var healthyStorages []string + for _, storage := range configuredStorages["virtual-storage"] { + if _, ok := tc.unhealthyStorages[storage]; ok { + continue + } - db := getDB(t) + healthyStorages = append(healthyStorages, storage) + } - configuredStorages := map[string][]string{"virtual-storage": {"primary", "secondary-1"}} + testhelper.SetHealthyNodes(t, ctx, tx, map[string]map[string][]string{ + "praefect-0": {"virtual-storage": healthyStorages}, + }) - if !tc.nonExistentRepository { - _, err := db.ExecContext(ctx, ` + if !tc.nonExistentRepository { + _, err := tx.ExecContext(ctx, ` INSERT INTO repositories (virtual_storage, relative_path, "primary") VALUES ('virtual-storage', 'relative-path', 'repository-primary') `) - require.NoError(t, err) - } + require.NoError(t, err) + } - for storage, generation := range tc.existingGenerations { - _, err := db.ExecContext(ctx, ` + for storage, generation := range tc.existingGenerations { + _, err := tx.ExecContext(ctx, ` INSERT INTO storage_repositories VALUES ('virtual-storage', 'relative-path', $1, $2) `, storage, generation) - require.NoError(t, err) - } + require.NoError(t, err) + } - for _, storage := range tc.existingAssignments { - _, err := db.ExecContext(ctx, ` + for _, storage := range tc.existingAssignments { + _, err := tx.ExecContext(ctx, ` INSERT INTO repository_assignments VALUES ('virtual-storage', 'relative-path', $1) `, storage) - require.NoError(t, err) - } + require.NoError(t, err) + } - _, err := db.ExecContext(ctx, ` + _, err = tx.ExecContext(ctx, ` INSERT INTO shard_primaries (shard_name, node_name, elected_by_praefect, elected_at) VALUES ('virtual-storage', 'virtual-storage-primary', 'ignored', now()) `) - require.NoError(t, err) - - store := NewPostgresRepositoryStore(db, configuredStorages) - outdated, err := store.GetPartiallyReplicatedRepositories(ctx, "virtual-storage", scope.useVirtualStoragePrimaries) - require.NoError(t, err) + require.NoError(t, err) - expected := []OutdatedRepository{ - { - RelativePath: "relative-path", - Primary: scope.primary, - Storages: tc.storageDetails, - }, - } + store := NewPostgresRepositoryStore(tx, configuredStorages) + outdated, err := store.GetPartiallyAvailableRepositories(ctx, "virtual-storage") + require.NoError(t, err) - if tc.storageDetails == nil { - expected = nil - } + expected := []PartiallyAvailableRepository{ + { + RelativePath: "relative-path", + Primary: "repository-primary", + Storages: tc.storageDetails, + }, + } - require.Equal(t, expected, outdated) - }) + if tc.storageDetails == nil { + expected = nil } + + require.Equal(t, expected, outdated) }) } } diff --git a/internal/praefect/service/info/dataloss.go b/internal/praefect/service/info/dataloss.go index 200f2bffb..3210884f0 100644 --- a/internal/praefect/service/info/dataloss.go +++ b/internal/praefect/service/info/dataloss.go @@ -3,42 +3,42 @@ package info import ( "context" - "gitlab.com/gitlab-org/gitaly/v14/internal/praefect/config" "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb" ) func (s *Server) DatalossCheck(ctx context.Context, req *gitalypb.DatalossCheckRequest) (*gitalypb.DatalossCheckResponse, error) { - outdatedRepos, err := s.rs.GetPartiallyReplicatedRepositories( - ctx, req.GetVirtualStorage(), s.conf.Failover.ElectionStrategy != config.ElectionStrategyPerRepository) + repos, err := s.rs.GetPartiallyAvailableRepositories(ctx, req.GetVirtualStorage()) if err != nil { return nil, err } - pbRepos := make([]*gitalypb.DatalossCheckResponse_Repository, 0, len(outdatedRepos)) - for _, outdatedRepo := range outdatedRepos { - readOnly := true + pbRepos := make([]*gitalypb.DatalossCheckResponse_Repository, 0, len(repos)) + for _, outdatedRepo := range repos { + unavailable := true storages := make([]*gitalypb.DatalossCheckResponse_Repository_Storage, 0, len(outdatedRepo.Storages)) for _, storage := range outdatedRepo.Storages { - if storage.Name == outdatedRepo.Primary && storage.BehindBy == 0 { - readOnly = false + if storage.ValidPrimary { + unavailable = false } storages = append(storages, &gitalypb.DatalossCheckResponse_Repository_Storage{ - Name: storage.Name, - BehindBy: int64(storage.BehindBy), - Assigned: storage.Assigned, + Name: storage.Name, + BehindBy: int64(storage.BehindBy), + Assigned: storage.Assigned, + Healthy: storage.Healthy, + ValidPrimary: storage.ValidPrimary, }) } - if !req.IncludePartiallyReplicated && !readOnly { + if !req.IncludePartiallyReplicated && !unavailable { continue } pbRepos = append(pbRepos, &gitalypb.DatalossCheckResponse_Repository{ RelativePath: outdatedRepo.RelativePath, Primary: outdatedRepo.Primary, - ReadOnly: readOnly, + Unavailable: unavailable, Storages: storages, }) } diff --git a/proto/go/gitalypb/praefect.pb.go b/proto/go/gitalypb/praefect.pb.go index b1ee17d2a..3049f8b73 100644 --- a/proto/go/gitalypb/praefect.pb.go +++ b/proto/go/gitalypb/praefect.pb.go @@ -243,10 +243,8 @@ type DatalossCheckRequest struct { unknownFields protoimpl.UnknownFields VirtualStorage string `protobuf:"bytes,1,opt,name=virtual_storage,json=virtualStorage,proto3" json:"virtual_storage,omitempty"` - // include_partially_replicated decides whether to include repositories which are fully up to date - // on the primary but are outdated on some secondaries. Such repositories are still writable and do - // not suffer from data loss. The data on the primary is not fully replicated which increases the - // chances of data loss following a failover. + // include_partially_unavailable indicates whether to include repositories which are available but + // are unavailable on some assigned storages. IncludePartiallyReplicated bool `protobuf:"varint,2,opt,name=include_partially_replicated,json=includePartiallyReplicated,proto3" json:"include_partially_replicated,omitempty"` } @@ -624,8 +622,8 @@ type DatalossCheckResponse_Repository struct { RelativePath string `protobuf:"bytes,1,opt,name=relative_path,json=relativePath,proto3" json:"relative_path,omitempty"` // storages on which the repository is outdated Storages []*DatalossCheckResponse_Repository_Storage `protobuf:"bytes,2,rep,name=storages,proto3" json:"storages,omitempty"` - // read_only indicates whether the repository is in read-only mode. - ReadOnly bool `protobuf:"varint,3,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` + // unavailable indicates whether the repository is in unavailable. + Unavailable bool `protobuf:"varint,3,opt,name=unavailable,proto3" json:"unavailable,omitempty"` // current primary storage of the repository Primary string `protobuf:"bytes,4,opt,name=primary,proto3" json:"primary,omitempty"` } @@ -676,9 +674,9 @@ func (x *DatalossCheckResponse_Repository) GetStorages() []*DatalossCheckRespons return nil } -func (x *DatalossCheckResponse_Repository) GetReadOnly() bool { +func (x *DatalossCheckResponse_Repository) GetUnavailable() bool { if x != nil { - return x.ReadOnly + return x.Unavailable } return false } @@ -701,6 +699,10 @@ type DatalossCheckResponse_Repository_Storage struct { BehindBy int64 `protobuf:"varint,2,opt,name=behind_by,json=behindBy,proto3" json:"behind_by,omitempty"` // assigned indicates whether the storage is assigned to host the repository. Assigned bool `protobuf:"varint,3,opt,name=assigned,proto3" json:"assigned,omitempty"` + // healthy indicates whether the storage is considered healthy by the consensus of Praefect nodes. + Healthy bool `protobuf:"varint,4,opt,name=healthy,proto3" json:"healthy,omitempty"` + // valid_primary indicates whether the storage is ready to act as the primary if necessary. + ValidPrimary bool `protobuf:"varint,5,opt,name=valid_primary,json=validPrimary,proto3" json:"valid_primary,omitempty"` } func (x *DatalossCheckResponse_Repository_Storage) Reset() { @@ -756,6 +758,20 @@ func (x *DatalossCheckResponse_Repository_Storage) GetAssigned() bool { return false } +func (x *DatalossCheckResponse_Repository_Storage) GetHealthy() bool { + if x != nil { + return x.Healthy + } + return false +} + +func (x *DatalossCheckResponse_Repository_Storage) GetValidPrimary() bool { + if x != nil { + return x.ValidPrimary + } + return false +} + type RepositoryReplicasResponse_RepositoryDetails struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -851,14 +867,14 @@ var file_praefect_proto_rawDesc = []byte{ 0x65, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x79, 0x5f, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1a, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x50, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x6c, 0x79, 0x52, 0x65, - 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x22, 0xf6, 0x02, 0x0a, 0x15, 0x44, 0x61, 0x74, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x22, 0xbb, 0x03, 0x0a, 0x15, 0x44, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x0c, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, - 0x1a, 0x8e, 0x02, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, + 0x1a, 0xd3, 0x02, 0x0a, 0x0a, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x4c, 0x0a, 0x08, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x73, @@ -866,104 +882,108 @@ var file_praefect_proto_rawDesc = []byte{ 0x44, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x08, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, - 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, 0x65, 0x61, 0x64, 0x4f, 0x6e, 0x6c, 0x79, 0x12, - 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x1a, 0x56, 0x0a, 0x07, 0x53, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x65, 0x68, 0x69, - 0x6e, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x62, 0x65, 0x68, - 0x69, 0x6e, 0x64, 0x42, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, - 0x64, 0x22, 0x4f, 0x0a, 0x19, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, - 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x32, - 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, 0x65, 0x70, 0x6f, - 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, - 0x72, 0x79, 0x22, 0xa3, 0x02, 0x0a, 0x1a, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, - 0x79, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x4e, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, 0x65, 0x70, 0x6f, - 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, - 0x79, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x07, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, - 0x79, 0x12, 0x50, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, 0x65, 0x70, - 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, - 0x72, 0x79, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x73, 0x1a, 0x63, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, - 0x79, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x32, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, - 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, - 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, - 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, - 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x22, 0xcf, 0x01, 0x0a, 0x17, 0x43, 0x6f, 0x6e, - 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x5f, - 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x76, - 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x25, 0x0a, - 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x10, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, - 0x65, 0x12, 0x37, 0x0a, 0x17, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x63, - 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x6c, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x63, 0x6f, 0x6e, - 0x63, 0x69, 0x6c, 0x6c, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x85, 0x02, 0x0a, 0x18, 0x43, - 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x72, 0x65, 0x70, 0x6f, 0x5f, - 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x70, 0x6f, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, - 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, - 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x12, 0x2d, - 0x0a, 0x12, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x63, 0x68, 0x65, 0x63, - 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x12, 0x1e, 0x0a, - 0x0b, 0x72, 0x65, 0x70, 0x6c, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x4a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x2b, 0x0a, - 0x11, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x73, 0x32, 0xee, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x61, 0x65, 0x66, 0x65, 0x63, 0x74, 0x49, - 0x6e, 0x66, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x5b, 0x0a, 0x12, 0x52, 0x65, - 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, - 0x12, 0x21, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, + 0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x75, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x75, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x6c, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x1a, 0x95, + 0x01, 0x0a, 0x07, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, + 0x0a, 0x09, 0x62, 0x65, 0x68, 0x69, 0x6e, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x08, 0x62, 0x65, 0x68, 0x69, 0x6e, 0x64, 0x42, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x61, + 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61, + 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x65, 0x61, 0x6c, 0x74, + 0x68, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x79, 0x12, 0x23, 0x0a, 0x0d, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x70, 0x72, 0x69, 0x6d, 0x61, + 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x50, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x4f, 0x0a, 0x19, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, 0x65, 0x70, - 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x10, 0x43, 0x6f, 0x6e, 0x73, 0x69, - 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x1f, 0x2e, 0x67, 0x69, - 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, - 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, - 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, - 0x79, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, - 0x12, 0x4c, 0x0a, 0x0d, 0x44, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x73, 0x43, 0x68, 0x65, 0x63, - 0x6b, 0x12, 0x1c, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x6c, - 0x6f, 0x73, 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1d, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x73, - 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x6a, - 0x0a, 0x17, 0x53, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, - 0x76, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x26, 0x2e, 0x67, 0x69, 0x74, 0x61, - 0x6c, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x61, 0x74, - 0x69, 0x76, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x27, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x75, - 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, - 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x61, 0x0a, 0x14, 0x53, 0x65, - 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x61, 0x63, 0x74, - 0x6f, 0x72, 0x12, 0x23, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x52, - 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, + 0x65, 0x73, 0x74, 0x12, 0x32, 0x0a, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, + 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x0a, 0x72, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x22, 0xa3, 0x02, 0x0a, 0x1a, 0x52, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4e, 0x0a, 0x07, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, + 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x69, + 0x63, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x07, 0x70, + 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x50, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, + 0x79, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x70, + 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x08, + 0x72, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x73, 0x1a, 0x63, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x32, 0x0a, + 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, + 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x0a, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, + 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x22, 0xcf, 0x01, + 0x0a, 0x17, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x76, 0x69, 0x72, + 0x74, 0x75, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x53, 0x74, 0x6f, 0x72, 0x61, + 0x67, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x66, + 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x53, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x17, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, + 0x65, 0x5f, 0x72, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x6c, 0x69, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x16, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x6c, 0x69, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, + 0x85, 0x02, 0x0a, 0x18, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x12, + 0x72, 0x65, 0x70, 0x6f, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x70, 0x61, + 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x70, 0x6f, 0x52, 0x65, + 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x27, 0x0a, 0x0f, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x73, 0x75, 0x6d, 0x12, 0x2d, 0x0a, 0x12, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x73, 0x75, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x11, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x73, + 0x75, 0x6d, 0x12, 0x1e, 0x0a, 0x0b, 0x72, 0x65, 0x70, 0x6c, 0x5f, 0x6a, 0x6f, 0x62, 0x5f, 0x69, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x65, 0x70, 0x6c, 0x4a, 0x6f, 0x62, + 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x11, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x5f, + 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, + 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x32, 0xee, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x61, 0x65, + 0x66, 0x65, 0x63, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x5b, 0x0a, 0x12, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x73, 0x12, 0x21, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x52, + 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, + 0x79, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x10, + 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x12, 0x1f, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, + 0x74, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x69, + 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x4c, 0x0a, 0x0d, 0x44, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x73, + 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x1c, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, + 0x44, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x44, 0x61, + 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x73, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x6a, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x12, 0x26, + 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, + 0x53, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, + 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x61, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x23, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x46, - 0x61, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x04, 0xf0, - 0x97, 0x28, 0x01, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, 0x67, 0x2f, 0x67, 0x69, 0x74, - 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x34, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, - 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x61, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x67, + 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x53, 0x65, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x1a, 0x04, 0xf0, 0x97, 0x28, 0x01, 0x42, 0x34, 0x5a, 0x32, 0x67, 0x69, 0x74, 0x6c, + 0x61, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x6c, 0x61, 0x62, 0x2d, 0x6f, 0x72, + 0x67, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2f, 0x76, 0x31, 0x34, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x70, 0x62, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/go/gitalypb/praefect_grpc.pb.go b/proto/go/gitalypb/praefect_grpc.pb.go index 435f2e849..5abdde92d 100644 --- a/proto/go/gitalypb/praefect_grpc.pb.go +++ b/proto/go/gitalypb/praefect_grpc.pb.go @@ -24,7 +24,7 @@ type PraefectInfoServiceClient interface { // back indicating which repos are consistent with the primary and which ones // need repair. ConsistencyCheck(ctx context.Context, in *ConsistencyCheckRequest, opts ...grpc.CallOption) (PraefectInfoService_ConsistencyCheckClient, error) - // DatalossCheck checks for outdated repository replicas. + // DatalossCheck checks for unavailable repositories. DatalossCheck(ctx context.Context, in *DatalossCheckRequest, opts ...grpc.CallOption) (*DatalossCheckResponse, error) // SetAuthoritativeStorage sets the authoritative storage for a repository on a given virtual storage. // This causes the current version of the repository on the authoritative storage to be considered the @@ -127,7 +127,7 @@ type PraefectInfoServiceServer interface { // back indicating which repos are consistent with the primary and which ones // need repair. ConsistencyCheck(*ConsistencyCheckRequest, PraefectInfoService_ConsistencyCheckServer) error - // DatalossCheck checks for outdated repository replicas. + // DatalossCheck checks for unavailable repositories. DatalossCheck(context.Context, *DatalossCheckRequest) (*DatalossCheckResponse, error) // SetAuthoritativeStorage sets the authoritative storage for a repository on a given virtual storage. // This causes the current version of the repository on the authoritative storage to be considered the diff --git a/proto/praefect.proto b/proto/praefect.proto index 946fef596..71198a687 100644 --- a/proto/praefect.proto +++ b/proto/praefect.proto @@ -17,7 +17,7 @@ service PraefectInfoService { // need repair. rpc ConsistencyCheck(ConsistencyCheckRequest) returns (stream ConsistencyCheckResponse); - // DatalossCheck checks for outdated repository replicas. + // DatalossCheck checks for unavailable repositories. rpc DatalossCheck(DatalossCheckRequest) returns (DatalossCheckResponse); // SetAuthoritativeStorage sets the authoritative storage for a repository on a given virtual storage. @@ -62,10 +62,8 @@ message SetAuthoritativeStorageResponse {} message DatalossCheckRequest { string virtual_storage = 1; - // include_partially_replicated decides whether to include repositories which are fully up to date - // on the primary but are outdated on some secondaries. Such repositories are still writable and do - // not suffer from data loss. The data on the primary is not fully replicated which increases the - // chances of data loss following a failover. + // include_partially_unavailable indicates whether to include repositories which are available but + // are unavailable on some assigned storages. bool include_partially_replicated = 2; } @@ -78,14 +76,18 @@ message DatalossCheckResponse { int64 behind_by = 2; // assigned indicates whether the storage is assigned to host the repository. bool assigned = 3; + // healthy indicates whether the storage is considered healthy by the consensus of Praefect nodes. + bool healthy = 4; + // valid_primary indicates whether the storage is ready to act as the primary if necessary. + bool valid_primary = 5; } // relative path of the repository with outdated replicas string relative_path = 1; // storages on which the repository is outdated repeated Storage storages = 2; - // read_only indicates whether the repository is in read-only mode. - bool read_only = 3; + // unavailable indicates whether the repository is in unavailable. + bool unavailable = 3; // current primary storage of the repository string primary = 4; diff --git a/ruby/proto/gitaly/praefect_pb.rb b/ruby/proto/gitaly/praefect_pb.rb index 8439cc121..0e10b2162 100644 --- a/ruby/proto/gitaly/praefect_pb.rb +++ b/ruby/proto/gitaly/praefect_pb.rb @@ -32,13 +32,15 @@ Google::Protobuf::DescriptorPool.generated_pool.build do add_message "gitaly.DatalossCheckResponse.Repository" do optional :relative_path, :string, 1 repeated :storages, :message, 2, "gitaly.DatalossCheckResponse.Repository.Storage" - optional :read_only, :bool, 3 + optional :unavailable, :bool, 3 optional :primary, :string, 4 end add_message "gitaly.DatalossCheckResponse.Repository.Storage" do optional :name, :string, 1 optional :behind_by, :int64, 2 optional :assigned, :bool, 3 + optional :healthy, :bool, 4 + optional :valid_primary, :bool, 5 end add_message "gitaly.RepositoryReplicasRequest" do optional :repository, :message, 1, "gitaly.Repository" diff --git a/ruby/proto/gitaly/praefect_services_pb.rb b/ruby/proto/gitaly/praefect_services_pb.rb index 9eb597889..a148f3357 100644 --- a/ruby/proto/gitaly/praefect_services_pb.rb +++ b/ruby/proto/gitaly/praefect_services_pb.rb @@ -20,7 +20,7 @@ module Gitaly # back indicating which repos are consistent with the primary and which ones # need repair. rpc :ConsistencyCheck, Gitaly::ConsistencyCheckRequest, stream(Gitaly::ConsistencyCheckResponse) - # DatalossCheck checks for outdated repository replicas. + # DatalossCheck checks for unavailable repositories. rpc :DatalossCheck, Gitaly::DatalossCheckRequest, Gitaly::DatalossCheckResponse # SetAuthoritativeStorage sets the authoritative storage for a repository on a given virtual storage. # This causes the current version of the repository on the authoritative storage to be considered the |