2
2
mirror of https://github.com/octoleo/restic.git synced 2024-06-07 11:30:49 +00:00

Introduce LoadTreeBlob and LoadDataBlob

This commit is contained in:
Alexander Neumann 2016-09-03 11:22:01 +02:00
parent 573410afab
commit 84f95a09d7
14 changed files with 67 additions and 32 deletions

View File

@ -61,7 +61,7 @@ func parseTime(str string) (time.Time, error) {
func (c CmdFind) findInTree(repo *repository.Repository, id restic.ID, path string) ([]findResult, error) { func (c CmdFind) findInTree(repo *repository.Repository, id restic.ID, path string) ([]findResult, error) {
debug.Log("restic.find", "checking tree %v\n", id) debug.Log("restic.find", "checking tree %v\n", id)
tree, err := restic.LoadTree(repo, id) tree, err := repo.LoadTree(id)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -47,7 +47,7 @@ func (cmd CmdLs) printNode(prefix string, n *restic.Node) string {
} }
func (cmd CmdLs) printTree(prefix string, repo *repository.Repository, id restic.ID) error { func (cmd CmdLs) printTree(prefix string, repo *repository.Repository, id restic.ID) error {
tree, err := restic.LoadTree(repo, id) tree, err := repo.LoadTree(id)
if err != nil { if err != nil {
return err return err
} }

View File

@ -21,7 +21,7 @@ func loadBlob(t *testing.T, repo *repository.Repository, id restic.ID, buf []byt
} }
func checkSavedFile(t *testing.T, repo *repository.Repository, treeID restic.ID, name string, rd io.Reader) { func checkSavedFile(t *testing.T, repo *repository.Repository, treeID restic.ID, name string, rd io.Reader) {
tree, err := restic.LoadTree(repo, treeID) tree, err := repo.LoadTree(treeID)
if err != nil { if err != nil {
t.Fatalf("LoadTree() returned error %v", err) t.Fatalf("LoadTree() returned error %v", err)
} }

View File

@ -376,7 +376,7 @@ func loadTreeWorker(repo restic.Repository,
} }
debug.Log("checker.loadTreeWorker", "load tree %v", treeID.Str()) debug.Log("checker.loadTreeWorker", "load tree %v", treeID.Str())
tree, err := restic.LoadTree(repo, treeID) tree, err := repo.LoadTree(treeID)
debug.Log("checker.loadTreeWorker", "load tree %v (%v) returned err: %v", tree, treeID.Str(), err) debug.Log("checker.loadTreeWorker", "load tree %v (%v) returned err: %v", tree, treeID.Str(), err)
job = treeJob{ID: treeID, error: err, Tree: tree} job = treeJob{ID: treeID, error: err, Tree: tree}
outCh = out outCh = out

View File

@ -6,7 +6,7 @@ package restic
func FindUsedBlobs(repo Repository, treeID ID, blobs BlobSet, seen BlobSet) error { func FindUsedBlobs(repo Repository, treeID ID, blobs BlobSet, seen BlobSet) error {
blobs.Insert(BlobHandle{ID: treeID, Type: TreeBlob}) blobs.Insert(BlobHandle{ID: treeID, Type: TreeBlob})
tree, err := LoadTree(repo, treeID) tree, err := repo.LoadTree(treeID)
if err != nil { if err != nil {
return err return err
} }

View File

@ -29,7 +29,7 @@ type dir struct {
func newDir(repo *repository.Repository, node *restic.Node, ownerIsRoot bool) (*dir, error) { func newDir(repo *repository.Repository, node *restic.Node, ownerIsRoot bool) (*dir, error) {
debug.Log("newDir", "new dir for %v (%v)", node.Name, node.Subtree.Str()) debug.Log("newDir", "new dir for %v (%v)", node.Name, node.Subtree.Str())
tree, err := restic.LoadTree(repo, *node.Subtree) tree, err := repo.LoadTree(*node.Subtree)
if err != nil { if err != nil {
debug.Log("newDir", " error loading tree %v: %v", node.Subtree.Str(), err) debug.Log("newDir", " error loading tree %v: %v", node.Subtree.Str(), err)
return nil, err return nil, err
@ -59,7 +59,7 @@ func replaceSpecialNodes(repo *repository.Repository, node *restic.Node) ([]*res
return []*restic.Node{node}, nil return []*restic.Node{node}, nil
} }
tree, err := restic.LoadTree(repo, *node.Subtree) tree, err := repo.LoadTree(*node.Subtree)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -69,7 +69,7 @@ func replaceSpecialNodes(repo *repository.Repository, node *restic.Node) ([]*res
func newDirFromSnapshot(repo *repository.Repository, snapshot SnapshotWithId, ownerIsRoot bool) (*dir, error) { func newDirFromSnapshot(repo *repository.Repository, snapshot SnapshotWithId, ownerIsRoot bool) (*dir, error) {
debug.Log("newDirFromSnapshot", "new dir for snapshot %v (%v)", snapshot.ID.Str(), snapshot.Tree.Str()) debug.Log("newDirFromSnapshot", "new dir for snapshot %v (%v)", snapshot.ID.Str(), snapshot.Tree.Str())
tree, err := restic.LoadTree(repo, *snapshot.Tree) tree, err := repo.LoadTree(*snapshot.Tree)
if err != nil { if err != nil {
debug.Log("newDirFromSnapshot", " loadTree(%v) failed: %v", snapshot.ID.Str(), err) debug.Log("newDirFromSnapshot", " loadTree(%v) failed: %v", snapshot.ID.Str(), err)
return nil, err return nil, err

View File

@ -218,10 +218,11 @@ func (node Node) createFileAt(path string, repo Repository) error {
buf = make([]byte, size) buf = make([]byte, size)
} }
buf, err := repo.LoadBlob(id, DataBlob, buf) n, err := repo.LoadDataBlob(id, buf)
if err != nil { if err != nil {
return err return err
} }
buf = buf[:n]
_, err = f.Write(buf) _, err = f.Write(buf)
if err != nil { if err != nil {

View File

@ -31,10 +31,11 @@ type Repository interface {
SaveAndEncrypt(BlobType, []byte, *ID) (ID, error) SaveAndEncrypt(BlobType, []byte, *ID) (ID, error)
SaveJSONUnpacked(FileType, interface{}) (ID, error) SaveJSONUnpacked(FileType, interface{}) (ID, error)
LoadJSONPack(BlobType, ID, interface{}) error
LoadJSONUnpacked(FileType, ID, interface{}) error LoadJSONUnpacked(FileType, ID, interface{}) error
LoadBlob(ID, BlobType, []byte) ([]byte, error)
LoadAndDecrypt(FileType, ID) ([]byte, error) LoadAndDecrypt(FileType, ID) ([]byte, error)
LoadTree(id ID) (*Tree, error)
LoadDataBlob(id ID, buf []byte) (int, error)
} }
// Deleter removes all data stored in a backend/repo. // Deleter removes all data stored in a backend/repo.

View File

@ -589,3 +589,45 @@ func (r *Repository) Delete() error {
func (r *Repository) Close() error { func (r *Repository) Close() error {
return r.be.Close() return r.be.Close()
} }
// LoadTree loads a tree from the repository.
func (r *Repository) LoadTree(id restic.ID) (*restic.Tree, error) {
size, err := r.idx.LookupSize(id, restic.TreeBlob)
if err != nil {
return nil, err
}
buf := make([]byte, size)
buf, err = r.LoadBlob(id, restic.TreeBlob, nil)
if err != nil {
return nil, err
}
t := &restic.Tree{}
err = json.Unmarshal(buf, t)
if err != nil {
return nil, err
}
return t, nil
}
// LoadDataBlob loads a data blob from the repository to the buffer.
func (r *Repository) LoadDataBlob(id restic.ID, buf []byte) (int, error) {
size, err := r.idx.LookupSize(id, restic.DataBlob)
if err != nil {
return 0, err
}
if len(buf) < int(size) {
return 0, errors.Errorf("buffer is too small for data blob (%d < %d)", len(buf), size)
}
buf, err = r.LoadBlob(id, restic.DataBlob, buf)
if err != nil {
return 0, err
}
return len(buf), err
}

View File

@ -39,7 +39,7 @@ func NewRestorer(repo Repository, id ID) (*Restorer, error) {
} }
func (res *Restorer) restoreTo(dst string, dir string, treeID ID) error { func (res *Restorer) restoreTo(dst string, dir string, treeID ID) error {
tree, err := LoadTree(res.repo, treeID) tree, err := res.repo.LoadTree(treeID)
if err != nil { if err != nil {
return res.Error(dir, nil, err) return res.Error(dir, nil, err)
} }

View File

@ -25,20 +25,6 @@ func (t Tree) String() string {
return fmt.Sprintf("Tree<%d nodes>", len(t.Nodes)) return fmt.Sprintf("Tree<%d nodes>", len(t.Nodes))
} }
type TreeLoader interface {
LoadJSONPack(BlobType, ID, interface{}) error
}
func LoadTree(repo TreeLoader, id ID) (*Tree, error) {
tree := &Tree{}
err := repo.LoadJSONPack(TreeBlob, id, tree)
if err != nil {
return nil, err
}
return tree, nil
}
// Equals returns true if t and other have exactly the same nodes. // Equals returns true if t and other have exactly the same nodes.
func (t Tree) Equals(other *Tree) bool { func (t Tree) Equals(other *Tree) bool {
if len(t.Nodes) != len(other.Nodes) { if len(t.Nodes) != len(other.Nodes) {
@ -85,6 +71,7 @@ func (t Tree) binarySearch(name string) (int, *Node, error) {
return pos, nil, errors.New("named node not found") return pos, nil, errors.New("named node not found")
} }
// Find returns a node with the given name.
func (t Tree) Find(name string) (*Node, error) { func (t Tree) Find(name string) (*Node, error) {
_, node, err := t.binarySearch(name) _, node, err := t.binarySearch(name)
return node, err return node, err

View File

@ -104,7 +104,7 @@ func TestLoadTree(t *testing.T) {
OK(t, repo.Flush()) OK(t, repo.Flush())
// load tree again // load tree again
tree2, err := restic.LoadTree(repo, id) tree2, err := repo.LoadTree(id)
OK(t, err) OK(t, err)
Assert(t, tree.Equals(tree2), Assert(t, tree.Equals(tree2),

View File

@ -156,17 +156,21 @@ func loadTreeWorker(wg *sync.WaitGroup, in <-chan loadTreeJob, load treeLoader,
} }
} }
// TreeLoader loads tree objects.
type TreeLoader interface {
LoadTree(restic.ID) (*restic.Tree, error)
}
const loadTreeWorkers = 10 const loadTreeWorkers = 10
// Tree walks the tree specified by id recursively and sends a job for each // Tree walks the tree specified by id recursively and sends a job for each
// file and directory it finds. When the channel done is closed, processing // file and directory it finds. When the channel done is closed, processing
// stops. // stops.
func Tree(repo restic.TreeLoader, id restic.ID, done chan struct{}, jobCh chan<- TreeJob) { func Tree(repo TreeLoader, id restic.ID, done chan struct{}, jobCh chan<- TreeJob) {
debug.Log("WalkTree", "start on %v, start workers", id.Str()) debug.Log("WalkTree", "start on %v, start workers", id.Str())
load := func(id restic.ID) (*restic.Tree, error) { load := func(id restic.ID) (*restic.Tree, error) {
tree := &restic.Tree{} tree, err := repo.LoadTree(id)
err := repo.LoadJSONPack(restic.TreeBlob, id, tree)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -95,9 +95,9 @@ type delayRepo struct {
delay time.Duration delay time.Duration
} }
func (d delayRepo) LoadJSONPack(t restic.BlobType, id restic.ID, dst interface{}) error { func (d delayRepo) LoadTree(id restic.ID) (*restic.Tree, error) {
time.Sleep(d.delay) time.Sleep(d.delay)
return d.repo.LoadJSONPack(t, id, dst) return d.repo.LoadTree(id)
} }
var repoFixture = filepath.Join("testdata", "walktree-test-repo.tar.gz") var repoFixture = filepath.Join("testdata", "walktree-test-repo.tar.gz")