From c8126c6c41c013fd857b1c9ba36fb837e4b843f3 Mon Sep 17 00:00:00 2001 From: James Fargher Date: Mon, 15 Jan 2024 11:34:09 +1300 Subject: backup: Write latest manifest file Manifests currently cannot restore the "latest" backup because it would require an expensive object-storage directory traversal. So instead it defers to the pointer layout. The problem with this is that you then loose manifest only features like setting the default branch properly. Here we write two manifests: the normal backup manifest as before and an additional "latest" manifest file. This latest manifest is overwritten on each backup taken. For WORM we would ideally not overwrite any files, but until this is implemented we need something to fill the latest restore gap. Changelog: changed --- internal/backup/locator.go | 29 ++++++++++++++++++++--------- internal/backup/locator_test.go | 9 +++++++-- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/internal/backup/locator.go b/internal/backup/locator.go index 1e1c42550..216037aea 100644 --- a/internal/backup/locator.go +++ b/internal/backup/locator.go @@ -294,17 +294,10 @@ func (l ManifestLocator) Commit(ctx context.Context, backup *Backup) (returnErr return err } - f, err := l.Sink.GetWriter(ctx, manifestPath(backup.Repository, backup.ID)) - if err != nil { + if err := l.writeManifest(ctx, backup, backup.ID); err != nil { return fmt.Errorf("manifest: commit: %w", err) } - defer func() { - if err := f.Close(); err != nil && returnErr == nil { - returnErr = fmt.Errorf("manifest: commit: %w", err) - } - }() - - if err := toml.NewEncoder(f).Encode(backup); err != nil { + if err := l.writeManifest(ctx, backup, "+latest"); err != nil { return fmt.Errorf("manifest: commit: %w", err) } @@ -340,6 +333,24 @@ func (l ManifestLocator) Find(ctx context.Context, repo storage.Repository, back return &backup, nil } +func (l ManifestLocator) writeManifest(ctx context.Context, backup *Backup, backupID string) (returnErr error) { + f, err := l.Sink.GetWriter(ctx, manifestPath(backup.Repository, backupID)) + if err != nil { + return fmt.Errorf("write manifest: %w", err) + } + defer func() { + if err := f.Close(); err != nil && returnErr == nil { + returnErr = fmt.Errorf("write manifest: %w", err) + } + }() + + if err := toml.NewEncoder(f).Encode(backup); err != nil { + return fmt.Errorf("write manifest: %w", err) + } + + return nil +} + func manifestPath(repo storage.Repository, backupID string) string { storageName := repo.GetStorageName() // Other locators strip the .git suffix off of relative paths. This suffix diff --git a/internal/backup/locator_test.go b/internal/backup/locator_test.go index 90cac3664..cca9ee8e8 100644 --- a/internal/backup/locator_test.go +++ b/internal/backup/locator_test.go @@ -470,7 +470,9 @@ custom_hooks_path = '%[1]s/%[2]s/001.custom_hooks.tar' require.NoError(t, l.Commit(ctx, incremental)) manifest := testhelper.MustReadFile(t, filepath.Join(backupPath, "manifests", repo.StorageName, repo.RelativePath, backupID+".toml")) - require.Equal(t, fmt.Sprintf(`object_format = 'sha1' + latestManifest := testhelper.MustReadFile(t, filepath.Join(backupPath, "manifests", repo.StorageName, repo.RelativePath, "+latest.toml")) + + expectedManifest := fmt.Sprintf(`object_format = 'sha1' [[steps]] bundle_path = '%[1]s/%[2]s/001.bundle' @@ -482,7 +484,10 @@ bundle_path = '%[1]s/%[2]s/002.bundle' ref_path = '%[1]s/%[2]s/002.refs' previous_ref_path = '%[1]s/%[2]s/001.refs' custom_hooks_path = '%[1]s/%[2]s/002.custom_hooks.tar' -`, repo.RelativePath, backupID), string(manifest)) +`, repo.RelativePath, backupID) + + require.Equal(t, expectedManifest, string(manifest)) + require.Equal(t, expectedManifest, string(latestManifest)) }) } -- cgit v1.2.3