Use array instead of hash for backend.ID

Since backend.ID is always a slice of constant length, use an array
instead of a slice. Mostly, arrays behave as slices, except that an
array cannot be nil, so use `*backend.ID` insteaf of `backend.ID` in
places where the absence of an ID is possible (e.g. for the Subtree of a
Node, which may not present when the node is a file node).

This change allows to directly use backend.ID as the the key for a map,
so that arbitrary data structures (e.g. a Set implemented as a
map[backend.ID]struct{}) can easily be formed.
This commit is contained in:
Alexander Neumann
2015-07-25 17:05:45 +02:00
parent 2fa6124545
commit 5cdcc99eba
31 changed files with 244 additions and 208 deletions

View File

@@ -185,23 +185,31 @@ func samePaths(expected, actual []string) bool {
return true
}
var errNoSnapshotFound = errors.New("no snapshot found")
func findLatestSnapshot(repo *repository.Repository, targets []string) (backend.ID, error) {
var (
latest time.Time
latestID backend.ID
found bool
)
for snapshotID := range repo.List(backend.Snapshot, make(chan struct{})) {
snapshot, err := restic.LoadSnapshot(repo, snapshotID)
if err != nil {
return nil, fmt.Errorf("Error listing snapshot: %v", err)
return backend.ID{}, fmt.Errorf("Error listing snapshot: %v", err)
}
if snapshot.Time.After(latest) && samePaths(snapshot.Paths, targets) {
latest = snapshot.Time
latestID = snapshotID
found = true
}
}
if !found {
return backend.ID{}, errNoSnapshotFound
}
return latestID, nil
}
@@ -258,27 +266,27 @@ func (cmd CmdBackup) Execute(args []string) error {
return err
}
var parentSnapshotID backend.ID
var parentSnapshotID *backend.ID
// Force using a parent
if !cmd.Force && cmd.Parent != "" {
parentSnapshotID, err = restic.FindSnapshot(repo, cmd.Parent)
id, err := restic.FindSnapshot(repo, cmd.Parent)
if err != nil {
return fmt.Errorf("invalid id %q: %v", cmd.Parent, err)
}
parentSnapshotID = &id
cmd.global.Verbosef("found parent snapshot %v\n", parentSnapshotID.Str())
}
// Find last snapshot to set it as parent, if not already set
if !cmd.Force && parentSnapshotID == nil {
parentSnapshotID, err = findLatestSnapshot(repo, target)
if err != nil {
return err
}
if parentSnapshotID != nil {
id, err := findLatestSnapshot(repo, target)
if err == nil {
cmd.global.Verbosef("using parent snapshot %v\n", parentSnapshotID)
parentSnapshotID = &id
} else if err != errNoSnapshotFound {
return err
}
}

View File

@@ -54,8 +54,6 @@ func (cmd CmdCat) Execute(args []string) error {
if tpe != "masterkey" && tpe != "config" {
id, err = backend.ParseID(args[1])
if err != nil {
id = nil
if tpe != "snapshot" {
return err
}

View File

@@ -114,7 +114,7 @@ func (c CmdFind) findInSnapshot(repo *repository.Repository, id backend.ID) erro
return err
}
results, err := c.findInTree(repo, sn.Tree, "")
results, err := c.findInTree(repo, *sn.Tree, "")
if err != nil {
return err
}

View File

@@ -56,7 +56,7 @@ func (cmd CmdLs) printTree(prefix string, repo *repository.Repository, id backen
cmd.global.Printf(cmd.printNode(prefix, entry) + "\n")
if entry.Type == "dir" && entry.Subtree != nil {
err = cmd.printTree(filepath.Join(prefix, entry.Name), repo, entry.Subtree)
err = cmd.printTree(filepath.Join(prefix, entry.Name), repo, *entry.Subtree)
if err != nil {
return err
}
@@ -97,5 +97,5 @@ func (cmd CmdLs) Execute(args []string) error {
cmd.global.Verbosef("snapshot of %v at %s:\n", sn.Paths, sn.Time)
return cmd.printTree("", repo, sn.Tree)
return cmd.printTree("", repo, *sn.Tree)
}

View File

@@ -1,6 +1,7 @@
package main
import (
"encoding/hex"
"fmt"
"io"
"os"
@@ -142,7 +143,8 @@ func (cmd CmdSnapshots) Execute(args []string) error {
if len(sn.Paths) == 0 {
continue
}
tab.Rows = append(tab.Rows, []interface{}{sn.ID()[:plen/2], sn.Time.Format(TimeFormat), sn.Hostname, sn.Paths[0]})
id := sn.ID()
tab.Rows = append(tab.Rows, []interface{}{hex.EncodeToString(id[:plen/2]), sn.Time.Format(TimeFormat), sn.Hostname, sn.Paths[0]})
if len(sn.Paths) > 1 {
for _, path := range sn.Paths[1:] {

View File

@@ -22,7 +22,7 @@ type dir struct {
}
func newDir(repo *repository.Repository, node *restic.Node) (*dir, error) {
tree, err := restic.LoadTree(repo, node.Subtree)
tree, err := restic.LoadTree(repo, *node.Subtree)
if err != nil {
return nil, err
}
@@ -39,7 +39,7 @@ func newDir(repo *repository.Repository, node *restic.Node) (*dir, error) {
}
func newDirFromSnapshot(repo *repository.Repository, snapshot SnapshotWithId) (*dir, error) {
tree, err := restic.LoadTree(repo, snapshot.Tree)
tree, err := restic.LoadTree(repo, *snapshot.Tree)
if err != nil {
return nil, err
}

View File

@@ -147,7 +147,7 @@ func TestMount(t *testing.T) {
checkSnapshots(repo, mountpoint, snapshotIDs)
// third backup, explicit incremental
cmdBackup(t, global, []string{env.testdata}, snapshotIDs[0])
cmdBackup(t, global, []string{env.testdata}, &snapshotIDs[0])
snapshotIDs = cmdList(t, global, "snapshots")
Assert(t, len(snapshotIDs) == 3,
"expected three snapshots, got %v", snapshotIDs)

View File

@@ -45,13 +45,15 @@ func cmdInit(t testing.TB, global GlobalOptions) {
t.Logf("repository initialized at %v", global.Repo)
}
func cmdBackup(t testing.TB, global GlobalOptions, target []string, parentID backend.ID) {
func cmdBackup(t testing.TB, global GlobalOptions, target []string, parentID *backend.ID) {
cmdBackupExcludes(t, global, target, parentID, nil)
}
func cmdBackupExcludes(t testing.TB, global GlobalOptions, target []string, parentID backend.ID, excludes []string) {
func cmdBackupExcludes(t testing.TB, global GlobalOptions, target []string, parentID *backend.ID, excludes []string) {
cmd := &CmdBackup{global: &global, Excludes: excludes}
cmd.Parent = parentID.String()
if parentID != nil {
cmd.Parent = parentID.String()
}
t.Logf("backing up %v", target)
@@ -136,7 +138,7 @@ func TestBackup(t *testing.T) {
cmdCheck(t, global)
// third backup, explicit incremental
cmdBackup(t, global, []string{env.testdata}, snapshotIDs[0])
cmdBackup(t, global, []string{env.testdata}, &snapshotIDs[0])
snapshotIDs = cmdList(t, global, "snapshots")
Assert(t, len(snapshotIDs) == 3,
"expected three snapshots, got %v", snapshotIDs)