Skip to content

Commit

Permalink
fix: btrfs destinations could not use btfs sources when reuse-snapsho…
Browse files Browse the repository at this point in the history
…ts was enabled
  • Loading branch information
sloonz committed Dec 19, 2024
1 parent 1e1b406 commit d48e3ad
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 8 deletions.
20 changes: 14 additions & 6 deletions sources/btrfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ func (s *btrfsSource) RemoveSnapshot(snapshot uback.Snapshot) error {

// Part of uback.Source interface
func (s *btrfsSource) CreateBackup(baseSnapshot *uback.Snapshot) (uback.Backup, io.ReadCloser, error) {
reused := false
snapshot := time.Now().UTC().Format(uback.SnapshotTimeFormat)
finalSnapshotPath := path.Join(s.snapshotsPath, snapshot)
tmpSnapshotPath := path.Join(s.snapshotsPath, fmt.Sprintf("_tmp-%s", snapshot))
Expand All @@ -131,9 +132,10 @@ func (s *btrfsSource) CreateBackup(baseSnapshot *uback.Snapshot) (uback.Backup,
}

if time.Now().UTC().Sub(t).Seconds() <= float64(s.reuseSnapshots) {
reused = true
snapshot = string(snapshots[0])
finalSnapshotPath = path.Join(s.snapshotsPath, snapshot)
tmpSnapshotPath = finalSnapshotPath
tmpSnapshotPath = path.Join(s.snapshotsPath, fmt.Sprintf("_tmp-%s", snapshot))
}
}
}
Expand All @@ -143,14 +145,18 @@ func (s *btrfsSource) CreateBackup(baseSnapshot *uback.Snapshot) (uback.Backup,
}

backup := uback.Backup{Snapshot: uback.Snapshot(snapshot), BaseSnapshot: baseSnapshot}
if tmpSnapshotPath != finalSnapshotPath {
if reused {
err := uback.RunCommand(btrfsLog, uback.BuildCommand(s.snapshotCommand, "-r", finalSnapshotPath, tmpSnapshotPath))
if err != nil {
return uback.Backup{}, nil, err
}
btrfsLog.Printf("reusing backup: %s", backup.Filename())
} else {
err := uback.RunCommand(btrfsLog, uback.BuildCommand(s.snapshotCommand, "-r", s.basePath, tmpSnapshotPath))
if err != nil {
return uback.Backup{}, nil, err
}
btrfsLog.Printf("creating backup: %s", backup.Filename())
} else {
btrfsLog.Printf("reusing backup: %s", backup.Filename())
}

args := []string{}
Expand All @@ -163,10 +169,12 @@ func (s *btrfsSource) CreateBackup(baseSnapshot *uback.Snapshot) (uback.Backup,
_ = uback.RunCommand(btrfsLog, uback.BuildCommand(s.deleteCommand, tmpSnapshotPath))
return err
}
if tmpSnapshotPath != finalSnapshotPath {
if reused {
cmd := uback.BuildCommand(s.deleteCommand, tmpSnapshotPath)
return uback.RunCommand(btrfsLog, cmd)
} else {
return os.Rename(tmpSnapshotPath, finalSnapshotPath)
}
return nil
})
}

Expand Down
7 changes: 5 additions & 2 deletions tests/src_btrfs_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ def test_btrfs_source(self):
self._test_src(self.tmpdir, source, dest, "receive-command=sudo btrfs receive", test_ignore=False, test_delete=True)

def test_btrfs_reuse_snapshots(self):
source = f"type=btrfs,path={self.tmpdir}/source,key-file={self.tmpdir}/backup.pub,state-file={self.tmpdir}/state.json,snapshots-path={self.tmpdir}/snapshots,full-interval=weekly," +\
source = f"type=btrfs,path={self.tmpdir}/source,no-encryption=1,state-file={self.tmpdir}/state.json,snapshots-path={self.tmpdir}/snapshots,full-interval=weekly," +\
"send-command=sudo btrfs send,delete-command=sudo btrfs subvolume delete,reuse-snapshots=1d"
dest = f"type=fs,@retention-policy=daily=3,key-file={self.tmpdir}/backup.key"
dest = f"type=btrfs,@retention-policy=daily=3"

ensure_dir(f"{self.tmpdir}/backups1")
ensure_dir(f"{self.tmpdir}/backups2")
Expand All @@ -62,3 +62,6 @@ def test_btrfs_reuse_snapshots(self):
self.assertEqual(set(os.listdir(f"{self.tmpdir}/snapshots")), {s})
with open(f"{self.tmpdir}/state.json") as fd:
self.assertEqual(json.load(fd), {"test1": s, "test2": s})

subprocess.check_call(["sudo", "btrfs", "subvolume", "delete", f"{self.tmpdir}/backups1/{s}"])
subprocess.check_call(["sudo", "btrfs", "subvolume", "delete", f"{self.tmpdir}/backups2/{s}"])

0 comments on commit d48e3ad

Please sign in to comment.