Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Cai <jcai@gitlab.com>2022-03-30 21:32:39 +0300
committerJohn Cai <jcai@gitlab.com>2022-03-30 21:32:39 +0300
commit131adc858a199fec86ad128d41b10340e0e9fabc (patch)
treeeddbbdbb1526a799dd26d34475f8ed5b0dec5a80
parent53ed969077dbd1611492fd67109dc1ef5e80aee5 (diff)
parente842c0b37ca67125383faf7f3f24b15d01f224ab (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.go18
-rw-r--r--internal/gitaly/service/internalgitaly/walkrepos.go9
-rw-r--r--internal/gitaly/service/internalgitaly/walkrepos_test.go29
-rw-r--r--internal/praefect/repocleaner/repository.go6
-rw-r--r--internal/praefect/repocleaner/repository_test.go46
-rw-r--r--proto/go/gitalypb/internal.pb.go75
-rw-r--r--proto/internal.proto5
-rw-r--r--ruby/proto/gitaly/internal_pb.rb2
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