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:
authorJames Fargher <jfargher@gitlab.com>2021-09-28 02:06:54 +0300
committerJames Fargher <jfargher@gitlab.com>2021-10-04 02:35:36 +0300
commitb578f037a03b37d6e8b7e5f9e21a6cc9ce1b6060 (patch)
tree2796cdfe4660e3b1b471c8ada8c046865a2c82aa
parent9589907901171fa95c456fc07387e0dd808231d4 (diff)
backup: Restore from incremental backups
Changelog: added
-rw-r--r--internal/backup/backup_test.go39
-rw-r--r--internal/backup/locator.go39
-rw-r--r--internal/backup/locator_test.go54
3 files changed, 118 insertions, 14 deletions
diff --git a/internal/backup/backup_test.go b/internal/backup/backup_test.go
index 88c060ae2..ab8304965 100644
--- a/internal/backup/backup_test.go
+++ b/internal/backup/backup_test.go
@@ -303,6 +303,45 @@ func testManagerRestore(t *testing.T, cfg config.Cfg, gitalyAddr string) {
},
expectExists: true,
},
+ {
+ desc: "single incremental",
+ locators: []string{"pointer"},
+ setup: func(t testing.TB) (*gitalypb.Repository, []string) {
+ const backupID = "abc123"
+ repo := createRepo(t, "incremental")
+ repoBackupPath := filepath.Join(path, repo.RelativePath)
+ backupPath := filepath.Join(repoBackupPath, backupID)
+ require.NoError(t, os.MkdirAll(backupPath, os.ModePerm))
+ require.NoError(t, os.WriteFile(filepath.Join(repoBackupPath, "LATEST"), []byte(backupID), os.ModePerm))
+ require.NoError(t, os.WriteFile(filepath.Join(backupPath, "LATEST"), []byte("001"), os.ModePerm))
+ bundlePath := filepath.Join(backupPath, "001.bundle")
+ gittest.BundleTestRepo(t, cfg, "gitlab-test.git", bundlePath)
+ return repo, []string{bundlePath}
+ },
+ expectExists: true,
+ },
+ {
+ desc: "many incrementals",
+ locators: []string{"pointer"},
+ setup: func(t testing.TB) (*gitalypb.Repository, []string) {
+ const backupID = "abc123"
+ repo := createRepo(t, "incremental")
+ repoBackupPath := filepath.Join(path, repo.RelativePath)
+ backupPath := filepath.Join(repoBackupPath, backupID)
+ require.NoError(t, os.MkdirAll(backupPath, os.ModePerm))
+ require.NoError(t, os.WriteFile(filepath.Join(repoBackupPath, "LATEST"), []byte(backupID), os.ModePerm))
+ require.NoError(t, os.WriteFile(filepath.Join(backupPath, "LATEST"), []byte("002"), os.ModePerm))
+
+ bundlePath1 := filepath.Join(backupPath, "001.bundle")
+ gittest.BundleTestRepo(t, cfg, "gitlab-test.git", bundlePath1, "master")
+
+ bundlePath2 := filepath.Join(backupPath, "002.bundle")
+ gittest.BundleTestRepo(t, cfg, "gitlab-test.git", bundlePath2, "feature")
+
+ return repo, []string{bundlePath1, bundlePath2}
+ },
+ expectExists: true,
+ },
} {
t.Run(tc.desc, func(t *testing.T) {
require.GreaterOrEqual(t, len(tc.locators), 1, "each test case must specify a locator")
diff --git a/internal/backup/locator.go b/internal/backup/locator.go
index 5ef75f7d3..81e53dcb1 100644
--- a/internal/backup/locator.go
+++ b/internal/backup/locator.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"path/filepath"
+ "strconv"
"strings"
"gitlab.com/gitlab-org/gitaly/v14/internal/helper/text"
@@ -98,25 +99,39 @@ func (l PointerLocator) CommitFull(ctx context.Context, full *Step) error {
//
// If there is no `LATEST` file, the result of the `Fallback` is used.
func (l PointerLocator) FindLatest(ctx context.Context, repo *gitalypb.Repository) (*Backup, error) {
- backupPath := strings.TrimSuffix(repo.RelativePath, ".git")
+ repoPath := strings.TrimSuffix(repo.RelativePath, ".git")
- backupID, err := l.findLatestID(ctx, backupPath)
+ backupID, err := l.findLatestID(ctx, repoPath)
if err != nil {
if l.Fallback != nil && errors.Is(err, ErrDoesntExist) {
return l.Fallback.FindLatest(ctx, repo)
}
- return nil, fmt.Errorf("pointer locator: %w", err)
+ return nil, fmt.Errorf("pointer locator: backup: %w", err)
}
- return &Backup{
- Steps: []Step{
- {
- BundlePath: filepath.Join(backupPath, backupID, "001.bundle"),
- RefPath: filepath.Join(backupPath, backupID, "001.refs"),
- CustomHooksPath: filepath.Join(backupPath, backupID, "001.custom_hooks.tar"),
- },
- },
- }, nil
+ backupPath := filepath.Join(repoPath, backupID)
+
+ latestIncrementID, err := l.findLatestID(ctx, backupPath)
+ if err != nil {
+ return nil, fmt.Errorf("pointer locator: latest incremental: %w", err)
+ }
+
+ max, err := strconv.Atoi(latestIncrementID)
+ if err != nil {
+ return nil, fmt.Errorf("pointer locator: latest incremental: %w", err)
+ }
+
+ var backup Backup
+
+ for i := 1; i <= max; i++ {
+ backup.Steps = append(backup.Steps, Step{
+ BundlePath: filepath.Join(backupPath, fmt.Sprintf("%03d.bundle", i)),
+ RefPath: filepath.Join(backupPath, fmt.Sprintf("%03d.refs", i)),
+ CustomHooksPath: filepath.Join(backupPath, fmt.Sprintf("%03d.custom_hooks.tar", i)),
+ })
+ }
+
+ return &backup, nil
}
func (l PointerLocator) findLatestID(ctx context.Context, backupPath string) (string, error) {
diff --git a/internal/backup/locator_test.go b/internal/backup/locator_test.go
index cc39bf66f..7bd3b48d7 100644
--- a/internal/backup/locator_test.go
+++ b/internal/backup/locator_test.go
@@ -100,8 +100,9 @@ func TestPointerLocator(t *testing.T) {
_, err := l.FindLatest(ctx, repo)
require.ErrorIs(t, err, ErrDoesntExist)
- require.NoError(t, os.MkdirAll(filepath.Join(backupPath, repo.RelativePath), 0o755))
+ require.NoError(t, os.MkdirAll(filepath.Join(backupPath, repo.RelativePath, backupID), 0o755))
require.NoError(t, os.WriteFile(filepath.Join(backupPath, repo.RelativePath, "LATEST"), []byte(backupID), 0o644))
+ require.NoError(t, os.WriteFile(filepath.Join(backupPath, repo.RelativePath, backupID, "LATEST"), []byte("003"), 0o644))
expected := &Backup{
Steps: []Step{
{
@@ -109,6 +110,16 @@ func TestPointerLocator(t *testing.T) {
RefPath: filepath.Join(repo.RelativePath, backupID, "001.refs"),
CustomHooksPath: filepath.Join(repo.RelativePath, backupID, "001.custom_hooks.tar"),
},
+ {
+ BundlePath: filepath.Join(repo.RelativePath, backupID, "002.bundle"),
+ RefPath: filepath.Join(repo.RelativePath, backupID, "002.refs"),
+ CustomHooksPath: filepath.Join(repo.RelativePath, backupID, "002.custom_hooks.tar"),
+ },
+ {
+ BundlePath: filepath.Join(repo.RelativePath, backupID, "003.bundle"),
+ RefPath: filepath.Join(repo.RelativePath, backupID, "003.refs"),
+ CustomHooksPath: filepath.Join(repo.RelativePath, backupID, "003.custom_hooks.tar"),
+ },
},
}
@@ -142,8 +153,9 @@ func TestPointerLocator(t *testing.T) {
require.NoError(t, err)
require.Equal(t, expectedFallback, fallbackFull)
- require.NoError(t, os.MkdirAll(filepath.Join(backupPath, repo.RelativePath), 0o755))
+ require.NoError(t, os.MkdirAll(filepath.Join(backupPath, repo.RelativePath, backupID), 0o755))
require.NoError(t, os.WriteFile(filepath.Join(backupPath, repo.RelativePath, "LATEST"), []byte(backupID), 0o644))
+ require.NoError(t, os.WriteFile(filepath.Join(backupPath, repo.RelativePath, backupID, "LATEST"), []byte("001"), 0o644))
expected := &Backup{
Steps: []Step{
{
@@ -158,5 +170,43 @@ func TestPointerLocator(t *testing.T) {
require.NoError(t, err)
require.Equal(t, expected, full)
})
+
+ t.Run("invalid backup LATEST", func(t *testing.T) {
+ backupPath := testhelper.TempDir(t)
+ var l Locator = PointerLocator{
+ Sink: NewFilesystemSink(backupPath),
+ }
+
+ ctx, cancel := testhelper.Context()
+ defer cancel()
+
+ _, err := l.FindLatest(ctx, repo)
+ require.ErrorIs(t, err, ErrDoesntExist)
+
+ require.NoError(t, os.MkdirAll(filepath.Join(backupPath, repo.RelativePath), 0o755))
+ require.NoError(t, os.WriteFile(filepath.Join(backupPath, repo.RelativePath, "LATEST"), []byte("invalid"), 0o644))
+ _, err = l.FindLatest(ctx, repo)
+ require.EqualError(t, err, "pointer locator: latest incremental: find latest ID: filesystem sink: get reader for \"TestPointerLocator/invalid/LATEST\": doesn't exist")
+ })
+
+ t.Run("invalid incremental LATEST", func(t *testing.T) {
+ backupPath := testhelper.TempDir(t)
+ var l Locator = PointerLocator{
+ Sink: NewFilesystemSink(backupPath),
+ }
+
+ ctx, cancel := testhelper.Context()
+ defer cancel()
+
+ _, err := l.FindLatest(ctx, repo)
+ require.ErrorIs(t, err, ErrDoesntExist)
+
+ require.NoError(t, os.MkdirAll(filepath.Join(backupPath, repo.RelativePath, backupID), 0o755))
+ require.NoError(t, os.WriteFile(filepath.Join(backupPath, repo.RelativePath, "LATEST"), []byte(backupID), 0o644))
+ require.NoError(t, os.WriteFile(filepath.Join(backupPath, repo.RelativePath, backupID, "LATEST"), []byte("invalid"), 0o644))
+
+ _, err = l.FindLatest(ctx, repo)
+ require.EqualError(t, err, "pointer locator: latest incremental: strconv.Atoi: parsing \"invalid\": invalid syntax")
+ })
})
}