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

locator.go « backup « internal - gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 6110240b9e5f229fa1eed5de0f6f0248826592da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package backup

import (
	"context"
	"errors"
	"fmt"
	"io"
	"path/filepath"
	"strings"

	"gitlab.com/gitlab-org/gitaly/v14/internal/helper/text"
	"gitlab.com/gitlab-org/gitaly/v14/proto/go/gitalypb"
)

// LegacyLocator locates backup paths for historic backups. This is the
// structure that gitlab used before incremental backups were introduced.
//
// Existing backup files are expected to be overwritten by the latest backup
// files.
//
// Structure:
//   <repo relative path>.bundle
//   <repo relative path>.refs
//   <repo relative path>/custom_hooks.tar
type LegacyLocator struct{}

// BeginFull returns the static paths for a legacy repository backup
func (l LegacyLocator) BeginFull(ctx context.Context, repo *gitalypb.Repository, backupID string) *Full {
	return l.newFull(repo)
}

// CommitFull is unused as the locations are static
func (l LegacyLocator) CommitFull(ctx context.Context, full *Full) error {
	return nil
}

// FindLatestFull returns the static paths for a legacy repository backup
func (l LegacyLocator) FindLatestFull(ctx context.Context, repo *gitalypb.Repository) (*Full, error) {
	return l.newFull(repo), nil
}

func (l LegacyLocator) newFull(repo *gitalypb.Repository) *Full {
	backupPath := strings.TrimSuffix(repo.RelativePath, ".git")

	return &Full{
		BundlePath:      backupPath + ".bundle",
		RefPath:         backupPath + ".refs",
		CustomHooksPath: filepath.Join(backupPath, "custom_hooks.tar"),
	}
}

// PointerLocator locates backup paths where each full backup is put into a
// unique timestamp directory and the latest backup taken is pointed to by a
// file named LATEST.
//
// Structure:
//   <repo relative path>/<backup id>/full.bundle
//   <repo relative path>/<backup id>/full.refs
//   <repo relative path>/<backup id>/custom_hooks.tar
//   <repo relative path>/LATEST
type PointerLocator struct {
	Sink     Sink
	Fallback Locator
}

// BeginFull returns paths for a new full backup
func (l PointerLocator) BeginFull(ctx context.Context, repo *gitalypb.Repository, backupID string) *Full {
	backupPath := strings.TrimSuffix(repo.RelativePath, ".git")

	return &Full{
		BundlePath:      filepath.Join(backupPath, backupID, "full.bundle"),
		RefPath:         filepath.Join(backupPath, backupID, "full.refs"),
		CustomHooksPath: filepath.Join(backupPath, backupID, "custom_hooks.tar"),
	}
}

// CommitFull persists the paths for a new backup so that it can be looked up by FindLatestFull
func (l PointerLocator) CommitFull(ctx context.Context, full *Full) error {
	bundleDir := filepath.Dir(full.BundlePath)
	backupID := filepath.Base(bundleDir)
	backupPath := filepath.Dir(bundleDir)
	return l.commitLatestID(ctx, backupPath, backupID)
}

// FindLatestFull returns the paths committed by the latest call to CommitFull.
//
// If there is no `LATEST` file, the result of the `Fallback` is used.
func (l PointerLocator) FindLatestFull(ctx context.Context, repo *gitalypb.Repository) (*Full, error) {
	backupPath := strings.TrimSuffix(repo.RelativePath, ".git")

	latest, err := l.findLatestID(ctx, backupPath)
	if err != nil {
		if l.Fallback != nil && errors.Is(err, ErrDoesntExist) {
			return l.Fallback.FindLatestFull(ctx, repo)
		}
		return nil, fmt.Errorf("pointer locator: %w", err)
	}

	return &Full{
		BundlePath:      filepath.Join(backupPath, latest, "full.bundle"),
		RefPath:         filepath.Join(backupPath, latest, "full.refs"),
		CustomHooksPath: filepath.Join(backupPath, latest, "custom_hooks.tar"),
	}, nil
}

func (l PointerLocator) findLatestID(ctx context.Context, backupPath string) (string, error) {
	r, err := l.Sink.GetReader(ctx, filepath.Join(backupPath, "LATEST"))
	if err != nil {
		return "", fmt.Errorf("find latest ID: %w", err)
	}
	defer r.Close()

	latest, err := io.ReadAll(r)
	if err != nil {
		return "", fmt.Errorf("find latest ID: %w", err)
	}

	return text.ChompBytes(latest), nil
}

func (l PointerLocator) commitLatestID(ctx context.Context, backupPath, backupID string) error {
	latest := strings.NewReader(backupID)
	if err := l.Sink.Write(ctx, filepath.Join(backupPath, "LATEST"), latest); err != nil {
		return fmt.Errorf("commit latest ID: %w", err)
	}
	return nil
}