Skip to content

Commit e6352d2

Browse files
Raderpulltheflower
andauthored
Add last commit size for repository (#1243)
Co-authored-by: Zhang ZeHua <pulltheflower@163.com>
1 parent 6577498 commit e6352d2

18 files changed

Lines changed: 466 additions & 57 deletions

File tree

_mocks/opencsg.com/csghub-server/builder/git/gitserver/mock_GitServer.go

Lines changed: 57 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

_mocks/opencsg.com/csghub-server/builder/rpc/mock_UserSvcClient.go

Lines changed: 5 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

_mocks/opencsg.com/csghub-server/builder/store/database/mock_UserStore.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

_mocks/opencsg.com/csghub-server/component/mock_RepoComponent.go

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/handler/repo.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2027,7 +2027,7 @@ func (h *RepoHandler) GetRepoSizeByBranch(ctx *gin.Context) {
20272027
branch := ctx.Param("branch")
20282028
repoType := common.RepoTypeFromContext(ctx)
20292029

2030-
size, err := h.c.GetRepoSizeByBranch(ctx.Request.Context(), repoType, namespace, name, branch, currentUser)
2030+
resp, err := h.c.GetRepoSizeByBranch(ctx.Request.Context(), repoType, namespace, name, branch, currentUser)
20312031
if err != nil {
20322032
slog.ErrorContext(ctx.Request.Context(), "Failed to get repo size", slog.String("repo_type", string(repoType)), slog.Any("error", err), slog.String("namespace", namespace), slog.String("name", name), slog.String("branch", branch))
20332033
if errors.Is(err, errorx.ErrForbidden) {
@@ -2042,8 +2042,8 @@ func (h *RepoHandler) GetRepoSizeByBranch(ctx *gin.Context) {
20422042
return
20432043
}
20442044

2045-
slog.Debug("Get repo size succeed", slog.String("repo_type", string(repoType)), slog.String("namespace", namespace), slog.String("name", name), slog.String("branch", branch), slog.Any("size", size))
2046-
httpbase.OK(ctx, size)
2045+
slog.Debug("Get repo size succeed", slog.String("repo_type", string(repoType)), slog.String("namespace", namespace), slog.String("name", name), slog.String("branch", branch), slog.Any("total_size", resp.TotalSize), slog.Any("last_commit_size", resp.LastCommitSize))
2046+
httpbase.OK(ctx, resp)
20472047
}
20482048

20492049
// BatchGetRepoExtra godoc

api/handler/repo_test.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,14 @@ func TestRepoHandler_GetRepoSizeByBranch(t *testing.T) {
8282
tester.WithKV("repo_type", types.ModelRepo)
8383

8484
// Set mock expectation
85-
expectedSize := int64(1024)
86-
tester.mocks.repo.EXPECT().GetRepoSizeByBranch(tester.Ctx(), types.ModelRepo, "u", "r", "main", "u").Return(expectedSize, nil)
85+
expectedResp := types.RepoSizeResponse{TotalSize: 1024, LastCommitSize: 512}
86+
tester.mocks.repo.EXPECT().GetRepoSizeByBranch(tester.Ctx(), types.ModelRepo, "u", "r", "main", "u").Return(expectedResp, nil)
8787

8888
// Execute request
8989
tester.Execute()
9090

9191
// Verify response
92-
tester.ResponseEq(t, http.StatusOK, tester.OKText, expectedSize)
92+
tester.ResponseEq(t, http.StatusOK, tester.OKText, expectedResp)
9393
}
9494

9595
func TestRepoHandler_ScanIndustryTags(t *testing.T) {
@@ -186,7 +186,7 @@ func TestRepoHandler_GetRepoSizeByBranch_Error(t *testing.T) {
186186
tester.WithKV("repo_type", types.ModelRepo)
187187

188188
// Set mock expectation with error
189-
tester.mocks.repo.EXPECT().GetRepoSizeByBranch(tester.Ctx(), types.ModelRepo, "u", "r", "main", "u").Return(int64(0), errors.New("failed to get repo size"))
189+
tester.mocks.repo.EXPECT().GetRepoSizeByBranch(tester.Ctx(), types.ModelRepo, "u", "r", "main", "u").Return(types.RepoSizeResponse{}, errors.New("failed to get repo size"))
190190

191191
// Execute request
192192
tester.Execute()
@@ -1985,13 +1985,16 @@ func TestRepoHandler_BatchGetRepoExtra(t *testing.T) {
19851985
})
19861986
tester.WithBody(t, types.BatchRepoExtraReq{RepoIDs: []int64{1, 2}}).WithUser()
19871987

1988-
tester.mocks.repo.EXPECT().BatchGetRepoExtra(tester.Ctx(), []int64{1, 2}, "u").Return([]types.RepoExtraItem{{RepoID: 1, Size: 100}, {RepoID: 2, Size: 200}}, nil)
1988+
tester.mocks.repo.EXPECT().BatchGetRepoExtra(tester.Ctx(), []int64{1, 2}, "u").Return([]types.RepoExtraItem{
1989+
{RepoID: 1, Size: 100, LastCommitSize: 50},
1990+
{RepoID: 2, Size: 200, LastCommitSize: 80},
1991+
}, nil)
19891992

19901993
tester.Execute()
19911994

19921995
tester.ResponseEq(t, http.StatusOK, tester.OKText, []types.RepoExtraItem{
1993-
{RepoID: 1, Size: 100},
1994-
{RepoID: 2, Size: 200},
1996+
{RepoID: 1, Size: 100, LastCommitSize: 50},
1997+
{RepoID: 2, Size: 200, LastCommitSize: 80},
19951998
})
19961999
})
19972000

builder/git/gitserver/gitaly/repo.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,139 @@ func (c *Client) GetRepoLfsSize(ctx context.Context, req gitserver.GetRepoInfoBy
387387
return totalSize, nil
388388
}
389389

390+
const getBlobsBatchSize = 1000
391+
392+
func (c *Client) GetLastCommitSize(ctx context.Context, req gitserver.GetRepoInfoByPathReq) (int64, error) {
393+
ctx, cancel := context.WithTimeout(ctx, c.timeout)
394+
defer cancel()
395+
396+
errCtx := errorx.Ctx().
397+
Set("repo_type", req.RepoType).
398+
Set("namespace", req.Namespace).
399+
Set("name", req.Name).
400+
Set("ref", req.Ref)
401+
402+
relativePath, err := c.BuildRelativePath(ctx, req.RepoType, req.Namespace, req.Name)
403+
if err != nil {
404+
return 0, err
405+
}
406+
407+
repository := &gitalypb.Repository{
408+
StorageName: c.config.GitalyServer.Storage,
409+
RelativePath: relativePath,
410+
}
411+
412+
// Get all file paths at HEAD
413+
listFilesReq := &gitalypb.ListFilesRequest{
414+
Repository: repository,
415+
Revision: []byte(req.Ref),
416+
}
417+
filesStream, err := c.commitClient.ListFiles(ctx, listFilesReq)
418+
if err != nil {
419+
return 0, errorx.ErrGitListFilesFailed(err, errCtx)
420+
}
421+
422+
var allPaths []string
423+
for {
424+
filesResp, err := filesStream.Recv()
425+
if err != nil {
426+
if err == io.EOF {
427+
break
428+
}
429+
return 0, errorx.ErrGitListFilesFailed(err, errCtx)
430+
}
431+
if filesResp != nil {
432+
for _, path := range filesResp.Paths {
433+
allPaths = append(allPaths, string(path))
434+
}
435+
}
436+
}
437+
438+
if len(allPaths) == 0 {
439+
return 0, nil
440+
}
441+
442+
// Get blob sizes in batches to avoid exceeding gRPC message limits
443+
var (
444+
lastCommitSize int64
445+
blobIDs []string
446+
)
447+
for i := 0; i < len(allPaths); i += getBlobsBatchSize {
448+
end := i + getBlobsBatchSize
449+
if end > len(allPaths) {
450+
end = len(allPaths)
451+
}
452+
batch := allPaths[i:end]
453+
454+
var revisionPaths []*gitalypb.GetBlobsRequest_RevisionPath
455+
for _, path := range batch {
456+
revisionPaths = append(revisionPaths, &gitalypb.GetBlobsRequest_RevisionPath{
457+
Revision: req.Ref,
458+
Path: []byte(path),
459+
})
460+
}
461+
462+
blobsStream, err := c.blobClient.GetBlobs(ctx, &gitalypb.GetBlobsRequest{
463+
Repository: repository,
464+
RevisionPaths: revisionPaths,
465+
Limit: 0,
466+
})
467+
if err != nil {
468+
return 0, errorx.ErrGitGetBlobsFailed(err, errCtx)
469+
}
470+
471+
for {
472+
blobResp, err := blobsStream.Recv()
473+
if err != nil {
474+
if err == io.EOF {
475+
break
476+
}
477+
return 0, errorx.ErrGitGetBlobsFailed(err, errCtx)
478+
}
479+
if blobResp != nil {
480+
lastCommitSize += blobResp.Size
481+
if blobResp.Oid != "" {
482+
blobIDs = append(blobIDs, blobResp.Oid)
483+
}
484+
}
485+
}
486+
}
487+
488+
// Get LFS file sizes in batches
489+
for i := 0; i < len(blobIDs); i += getBlobsBatchSize {
490+
end := i + getBlobsBatchSize
491+
if end > len(blobIDs) {
492+
end = len(blobIDs)
493+
}
494+
batch := blobIDs[i:end]
495+
496+
pointersStream, err := c.blobClient.GetLFSPointers(ctx, &gitalypb.GetLFSPointersRequest{
497+
Repository: repository,
498+
BlobIds: batch,
499+
})
500+
if err != nil {
501+
return 0, errorx.ErrGitGetLfsPointersFailed(err, errCtx)
502+
}
503+
504+
for {
505+
pointerResp, err := pointersStream.Recv()
506+
if err != nil {
507+
if err == io.EOF {
508+
break
509+
}
510+
return 0, errorx.ErrGitGetLfsPointersFailed(err, errCtx)
511+
}
512+
if pointerResp != nil {
513+
for _, pointer := range pointerResp.LfsPointers {
514+
lastCommitSize += pointer.FileSize
515+
}
516+
}
517+
}
518+
}
519+
520+
return lastCommitSize, nil
521+
}
522+
390523
func (c *Client) CreateFork(ctx context.Context, req gitserver.CreateForkReq) error {
391524
ctx, cancel := context.WithTimeout(ctx, c.timeout)
392525
defer cancel()

0 commit comments

Comments
 (0)