diff options
author | John Cai <jcai@gitlab.com> | 2022-03-30 21:32:39 +0300 |
---|---|---|
committer | John Cai <jcai@gitlab.com> | 2022-03-30 21:32:39 +0300 |
commit | 131adc858a199fec86ad128d41b10340e0e9fabc (patch) | |
tree | eddbbdbb1526a799dd26d34475f8ed5b0dec5a80 | |
parent | 53ed969077dbd1611492fd67109dc1ef5e80aee5 (diff) | |
parent | e842c0b37ca67125383faf7f3f24b15d01f224ab (diff) |
Merge branch 'jc-repo-cleaner-grace-period' into 'master'
repocleaner: Only log repositories that have a mod time older than 24 hours and are not in the Praefect DB
See merge request gitlab-org/gitaly!4449
-rw-r--r-- | cmd/praefect/subcmd_list_untracked_repositories_test.go | 18 | ||||
-rw-r--r-- | internal/gitaly/service/internalgitaly/walkrepos.go | 9 | ||||
-rw-r--r-- | internal/gitaly/service/internalgitaly/walkrepos_test.go | 29 | ||||
-rw-r--r-- | internal/praefect/repocleaner/repository.go | 6 | ||||
-rw-r--r-- | internal/praefect/repocleaner/repository_test.go | 46 | ||||
-rw-r--r-- | proto/go/gitalypb/internal.pb.go | 75 | ||||
-rw-r--r-- | proto/internal.proto | 5 | ||||
-rw-r--r-- | ruby/proto/gitaly/internal_pb.rb | 2 |
8 files changed, 121 insertions, 69 deletions
diff --git a/cmd/praefect/subcmd_list_untracked_repositories_test.go b/cmd/praefect/subcmd_list_untracked_repositories_test.go index 0f7a93b1e..a2c251a81 100644 --- a/cmd/praefect/subcmd_list_untracked_repositories_test.go +++ b/cmd/praefect/subcmd_list_untracked_repositories_test.go @@ -5,8 +5,10 @@ import ( "context" "flag" "fmt" + "os" "strings" "testing" + "time" "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitaly/v14/client" @@ -53,9 +55,18 @@ func TestListUntrackedRepositories_Exec(t *testing.T) { g2Cfg := testcfg.Build(t, testcfg.WithStorages("gitaly-2")) // Repositories not managed by praefect. - repo1, _ := gittest.InitRepo(t, g1Cfg, g1Cfg.Storages[0]) - repo2, _ := gittest.InitRepo(t, g1Cfg, g1Cfg.Storages[0]) - repo3, _ := gittest.InitRepo(t, g2Cfg, g2Cfg.Storages[0]) + repo1, repo1Path := gittest.InitRepo(t, g1Cfg, g1Cfg.Storages[0]) + repo2, repo2Path := gittest.InitRepo(t, g1Cfg, g1Cfg.Storages[0]) + _, _ = gittest.InitRepo(t, g2Cfg, g2Cfg.Storages[0]) + + require.NoError(t, os.Chtimes( + repo1Path, + time.Now().Add(-(24*time.Hour+1*time.Second)), + time.Now().Add(-(24*time.Hour+1*time.Second)))) + require.NoError(t, os.Chtimes( + repo2Path, + time.Now().Add(-(24*time.Hour+1*time.Second)), + time.Now().Add(-(24*time.Hour+1*time.Second)))) g1Addr := testserver.RunGitalyServer(t, g1Cfg, nil, setup.RegisterAll, testserver.WithDisablePraefect()) g2Addr := testserver.RunGitalyServer(t, g2Cfg, nil, setup.RegisterAll, testserver.WithDisablePraefect()) @@ -99,7 +110,6 @@ func TestListUntrackedRepositories_Exec(t *testing.T) { "The following repositories were found on disk, but missing from the tracking database:", fmt.Sprintf(`{"relative_path":%q,"storage":"gitaly-1","virtual_storage":"praefect"}`, repo1.RelativePath), fmt.Sprintf(`{"relative_path":%q,"storage":"gitaly-1","virtual_storage":"praefect"}`, repo2.RelativePath), - fmt.Sprintf(`{"relative_path":%q,"storage":"gitaly-2","virtual_storage":"praefect"}`, repo3.RelativePath), "", // an empty extra element required as each line ends with "delimiter" and strings.Split returns all parts } require.ElementsMatch(t, exp, strings.Split(out.String(), "\n")) diff --git a/internal/gitaly/service/internalgitaly/walkrepos.go b/internal/gitaly/service/internalgitaly/walkrepos.go index 08979f92b..71a023fdd 100644 --- a/internal/gitaly/service/internalgitaly/walkrepos.go +++ b/internal/gitaly/service/internalgitaly/walkrepos.go @@ -9,6 +9,7 @@ import ( "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/timestamppb" ) func (s *server) WalkRepos(req *gitalypb.WalkReposRequest, stream gitalypb.InternalGitaly_WalkReposServer) error { @@ -55,8 +56,14 @@ func walkStorage(ctx context.Context, storagePath string, stream gitalypb.Intern return err } + gitDirInfo, err := os.Stat(path) + if err != nil { + return err + } + if err := stream.Send(&gitalypb.WalkReposResponse{ - RelativePath: relPath, + RelativePath: relPath, + ModificationTime: timestamppb.New(gitDirInfo.ModTime()), }); err != nil { return err } diff --git a/internal/gitaly/service/internalgitaly/walkrepos_test.go b/internal/gitaly/service/internalgitaly/walkrepos_test.go index c4aad9fcd..23a3aaec4 100644 --- a/internal/gitaly/service/internalgitaly/walkrepos_test.go +++ b/internal/gitaly/service/internalgitaly/walkrepos_test.go @@ -6,6 +6,7 @@ import ( "path/filepath" "sync" "testing" + "time" "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitaly/v14/internal/git/gittest" @@ -42,16 +43,26 @@ func TestWalkRepos(t *testing.T) { // file walk happens lexicographically, so we delete repository in the middle // of the seqeuence to ensure the walk proceeds normally - testRepo1, _ := gittest.CloneRepo(t, cfg, cfg.Storages[0], gittest.CloneRepoOpts{ + testRepo1, testRepo1Path := gittest.CloneRepo(t, cfg, cfg.Storages[0], gittest.CloneRepoOpts{ RelativePath: "a", }) deletedRepo, _ := gittest.CloneRepo(t, cfg, cfg.Storages[0], gittest.CloneRepoOpts{ RelativePath: "b", }) - testRepo2, _ := gittest.CloneRepo(t, cfg, cfg.Storages[0], gittest.CloneRepoOpts{ + testRepo2, testRepo2Path := gittest.CloneRepo(t, cfg, cfg.Storages[0], gittest.CloneRepoOpts{ RelativePath: "c", }) + modifiedDate := time.Now().Add(-1 * time.Hour) + require.NoError( + t, + os.Chtimes(testRepo1Path, time.Now(), modifiedDate), + ) + require.NoError( + t, + os.Chtimes(testRepo2Path, time.Now(), modifiedDate), + ) + // to test a directory being deleted during a walk, we must delete a directory after // the file walk has started. To achieve that, we wrap the server to pass down a wrapped // stream that allows us to hook in to stream responses. We then delete 'b' when @@ -93,14 +104,14 @@ func TestWalkRepos(t *testing.T) { require.NoError(t, err) actualRepos := consumeWalkReposStream(t, stream) - require.Equal(t, []string{ - testRepo1.GetRelativePath(), - testRepo2.GetRelativePath(), - }, actualRepos) + require.Equal(t, testRepo1.GetRelativePath(), actualRepos[0].GetRelativePath()) + require.Equal(t, modifiedDate.UTC(), actualRepos[0].GetModificationTime().AsTime()) + require.Equal(t, testRepo2.GetRelativePath(), actualRepos[1].GetRelativePath()) + require.Equal(t, modifiedDate.UTC(), actualRepos[1].GetModificationTime().AsTime()) } -func consumeWalkReposStream(t *testing.T, stream gitalypb.InternalGitaly_WalkReposClient) []string { - var repos []string +func consumeWalkReposStream(t *testing.T, stream gitalypb.InternalGitaly_WalkReposClient) []*gitalypb.WalkReposResponse { + var repos []*gitalypb.WalkReposResponse for { resp, err := stream.Recv() if err == io.EOF { @@ -108,7 +119,7 @@ func consumeWalkReposStream(t *testing.T, stream gitalypb.InternalGitaly_WalkRep } else { require.NoError(t, err) } - repos = append(repos, resp.RelativePath) + repos = append(repos, resp) } return repos } diff --git a/internal/praefect/repocleaner/repository.go b/internal/praefect/repocleaner/repository.go index dea0ad17c..aeff3ac7d 100644 --- a/internal/praefect/repocleaner/repository.go +++ b/internal/praefect/repocleaner/repository.go @@ -187,6 +187,12 @@ func (wr *Walker) ExecOnRepositories(ctx context.Context, virtualStorage, storag break } + // repositories that are in the process of being created, where + // they do not yet have a record in Praefect. + if res.GetModificationTime().AsTime().After(time.Now().Add(-24 * time.Hour)) { + continue + } + batch = append(batch, res.RelativePath) if len(batch) == cap(batch) { diff --git a/internal/praefect/repocleaner/repository_test.go b/internal/praefect/repocleaner/repository_test.go index f07b4d9e7..6924d3069 100644 --- a/internal/praefect/repocleaner/repository_test.go +++ b/internal/praefect/repocleaner/repository_test.go @@ -2,6 +2,7 @@ package repocleaner import ( "context" + "os" "sync/atomic" "testing" "time" @@ -71,19 +72,23 @@ func TestRunner_Run(t *testing.T) { RepositoriesInBatch: 2, } + // each gitaly has an extra repo-4.git repository gittest.CloneRepo(t, g1Cfg, g1Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: repo1RelPath}) gittest.CloneRepo(t, g1Cfg, g1Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: repo2RelPath}) gittest.CloneRepo(t, g1Cfg, g1Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: repo3RelPath}) + _, repo4Path := gittest.CloneRepo(t, g1Cfg, g1Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: "repo-4.git"}) + require.NoError(t, os.Chtimes(repo4Path, time.Now().Add(-25*time.Hour), time.Now().Add(-25*time.Hour))) - // second gitaly is missing repo-3.git repository gittest.CloneRepo(t, g2Cfg, g2Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: repo1RelPath}) gittest.CloneRepo(t, g2Cfg, g2Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: repo2RelPath}) + _, repo4Path = gittest.CloneRepo(t, g2Cfg, g2Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: "repo-4.git"}) + require.NoError(t, os.Chtimes(repo4Path, time.Now().Add(-25*time.Hour), time.Now().Add(-25*time.Hour))) - // third gitaly has an extra repo-4.git repository gittest.CloneRepo(t, g3Cfg, g3Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: repo1RelPath}) gittest.CloneRepo(t, g3Cfg, g3Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: repo2RelPath}) gittest.CloneRepo(t, g3Cfg, g3Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: repo3RelPath}) - gittest.CloneRepo(t, g3Cfg, g3Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: "repo-4.git"}) + _, repo4Path = gittest.CloneRepo(t, g3Cfg, g3Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: "repo-4.git"}) + require.NoError(t, os.Chtimes(repo4Path, time.Now().Add(-25*time.Hour), time.Now().Add(-25*time.Hour))) ctx, cancel := context.WithCancel(testhelper.Context(t)) repoStore := datastore.NewPostgresRepositoryStore(db.DB, nil) @@ -125,33 +130,18 @@ func TestRunner_Run(t *testing.T) { var iteration int32 runner := NewRunner(cfg, logger, praefect.StaticHealthChecker{virtualStorage: []string{storage1, storage2, storage3}}, nodeSet.Connections(), storageCleanup, storageCleanup, actionStub{ PerformMethod: func(ctx context.Context, argVirtualStoage, argStorage string, notExisting []string) error { - assert.Equal(t, virtualStorage, argVirtualStoage) - // Because action invocation happens for batches each run could result - // multiple invocations of the action. Amount of invocations can be calculated - // as amount of storage repositories divided on the size of the batch and rounded up. - // For storages: - // 'gitaly-1' is it 3 repos / 2 = 2 calls [0,1] - // 'gitaly-2' is it 2 repos / 2 = 1 call [2] - // 'gitaly-3' is it 4 repos / 2 = 2 calls [3,4] + // There should be three iterations, as each storage has + // one repository that is unused by praefect. + atomic.AddInt32(&iteration, 1) + i := atomic.LoadInt32(&iteration) - switch i { - case 0, 1: - assert.Equal(t, storage1, argStorage) - assert.ElementsMatch(t, nil, notExisting) - case 2: - assert.Equal(t, storage2, argStorage) - assert.ElementsMatch(t, []string{repo1RelPath}, notExisting) - case 3: - assert.Equal(t, storage3, argStorage) - assert.ElementsMatch(t, nil, notExisting) - case 4: - assert.Equal(t, storage3, argStorage) + assert.Equal(t, virtualStorage, argVirtualStoage) + assert.Equal(t, []string{"repo-4.git"}, notExisting) + + if i == 3 { // Terminates the loop. defer cancel() - assert.Equal(t, []string{"repo-4.git"}, notExisting) - return nil } - atomic.AddInt32(&iteration, 1) return nil }, }) @@ -169,7 +159,6 @@ func TestRunner_Run(t *testing.T) { } waitReceive(t, done) - require.Equal(t, int32(4), atomic.LoadInt32(&iteration)) require.GreaterOrEqual(t, len(loggerHook.AllEntries()), 2) require.Equal( t, @@ -216,7 +205,8 @@ func TestRunner_Run_noAvailableStorages(t *testing.T) { RepositoriesInBatch: 2, } - gittest.CloneRepo(t, g1Cfg, g1Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: repo1RelPath}) + _, repoPath := gittest.CloneRepo(t, g1Cfg, g1Cfg.Storages[0], gittest.CloneRepoOpts{RelativePath: repo1RelPath}) + require.NoError(t, os.Chtimes(repoPath, time.Now().Add(-25*time.Hour), time.Now().Add(-25*time.Hour))) ctx, cancel := context.WithCancel(testhelper.Context(t)) repoStore := datastore.NewPostgresRepositoryStore(db.DB, nil) diff --git a/proto/go/gitalypb/internal.pb.go b/proto/go/gitalypb/internal.pb.go index b5ddcb5ef..d7b604b54 100644 --- a/proto/go/gitalypb/internal.pb.go +++ b/proto/go/gitalypb/internal.pb.go @@ -9,6 +9,7 @@ package gitalypb import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" ) @@ -73,6 +74,10 @@ type WalkReposResponse struct { unknownFields protoimpl.UnknownFields RelativePath string `protobuf:"bytes,1,opt,name=relative_path,json=relativePath,proto3" json:"relative_path,omitempty"` + // modification_time is the modification time of the repository directory. + // This can be used as a proxy for when the repository was last + // modified. + ModificationTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=modification_time,json=modificationTime,proto3" json:"modification_time,omitempty"` } func (x *WalkReposResponse) Reset() { @@ -114,29 +119,43 @@ func (x *WalkReposResponse) GetRelativePath() string { return "" } +func (x *WalkReposResponse) GetModificationTime() *timestamppb.Timestamp { + if x != nil { + return x.ModificationTime + } + return nil +} + var File_internal_proto protoreflect.FileDescriptor var file_internal_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x1a, 0x0a, 0x6c, 0x69, 0x6e, 0x74, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x3b, 0x0a, 0x10, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70, 0x6f, - 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0c, 0x73, 0x74, 0x6f, 0x72, - 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, - 0x88, 0xc6, 0x2c, 0x01, 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4e, 0x61, 0x6d, - 0x65, 0x22, 0x38, 0x0a, 0x11, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 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, 0x32, 0x5e, 0x0a, 0x0e, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x47, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x12, 0x4c, 0x0a, - 0x09, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x18, 0x2e, 0x67, 0x69, 0x74, - 0x61, 0x6c, 0x79, 0x2e, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x57, 0x61, - 0x6c, 0x6b, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x08, 0xfa, 0x97, 0x28, 0x04, 0x08, 0x02, 0x10, 0x02, 0x30, 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, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x3b, 0x0a, 0x10, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70, + 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0c, 0x73, 0x74, 0x6f, + 0x72, 0x61, 0x67, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x04, 0x88, 0xc6, 0x2c, 0x01, 0x52, 0x0b, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x11, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70, 0x6f, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 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, 0x47, 0x0a, + 0x11, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x32, 0x5e, 0x0a, 0x0e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x47, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x12, 0x4c, 0x0a, 0x09, 0x57, 0x61, 0x6c, 0x6b, + 0x52, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x18, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x57, + 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70, 0x6f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x19, 0x2e, 0x67, 0x69, 0x74, 0x61, 0x6c, 0x79, 0x2e, 0x57, 0x61, 0x6c, 0x6b, 0x52, 0x65, 0x70, + 0x6f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0xfa, 0x97, 0x28, 0x04, + 0x08, 0x02, 0x10, 0x02, 0x30, 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 ( @@ -153,17 +172,19 @@ func file_internal_proto_rawDescGZIP() []byte { var file_internal_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_internal_proto_goTypes = []interface{}{ - (*WalkReposRequest)(nil), // 0: gitaly.WalkReposRequest - (*WalkReposResponse)(nil), // 1: gitaly.WalkReposResponse + (*WalkReposRequest)(nil), // 0: gitaly.WalkReposRequest + (*WalkReposResponse)(nil), // 1: gitaly.WalkReposResponse + (*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp } var file_internal_proto_depIdxs = []int32{ - 0, // 0: gitaly.InternalGitaly.WalkRepos:input_type -> gitaly.WalkReposRequest - 1, // 1: gitaly.InternalGitaly.WalkRepos:output_type -> gitaly.WalkReposResponse - 1, // [1:2] is the sub-list for method output_type - 0, // [0:1] is the sub-list for method input_type - 0, // [0:0] is the sub-list for extension type_name - 0, // [0:0] is the sub-list for extension extendee - 0, // [0:0] is the sub-list for field type_name + 2, // 0: gitaly.WalkReposResponse.modification_time:type_name -> google.protobuf.Timestamp + 0, // 1: gitaly.InternalGitaly.WalkRepos:input_type -> gitaly.WalkReposRequest + 1, // 2: gitaly.InternalGitaly.WalkRepos:output_type -> gitaly.WalkReposResponse + 2, // [2:3] is the sub-list for method output_type + 1, // [1:2] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name } func init() { file_internal_proto_init() } diff --git a/proto/internal.proto b/proto/internal.proto index 33e1d96ae..1cacb3bc5 100644 --- a/proto/internal.proto +++ b/proto/internal.proto @@ -5,6 +5,7 @@ package gitaly; option go_package = "gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"; import "lint.proto"; +import "google/protobuf/timestamp.proto"; // InternalGitaly is a gRPC service meant to be served by a Gitaly node, but // only reachable by Praefect or other Gitalies @@ -25,4 +26,8 @@ message WalkReposRequest { message WalkReposResponse { string relative_path = 1; + // modification_time is the modification time of the repository directory. + // This can be used as a proxy for when the repository was last + // modified. + google.protobuf.Timestamp modification_time = 2; } diff --git a/ruby/proto/gitaly/internal_pb.rb b/ruby/proto/gitaly/internal_pb.rb index 0b9206b10..ecf1659b4 100644 --- a/ruby/proto/gitaly/internal_pb.rb +++ b/ruby/proto/gitaly/internal_pb.rb @@ -2,6 +2,7 @@ # source: internal.proto require 'lint_pb' +require 'google/protobuf/timestamp_pb' require 'google/protobuf' Google::Protobuf::DescriptorPool.generated_pool.build do @@ -11,6 +12,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do end add_message "gitaly.WalkReposResponse" do optional :relative_path, :string, 1 + optional :modification_time, :message, 2, "google.protobuf.Timestamp" end end end |