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) {
debug.Log("restic.find", "checking tree %v\n", id)
tree, err := restic.LoadTree(repo, id)
tree, err := repo.LoadTree(id)
if err != nil {
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 {
tree, err := restic.LoadTree(repo, id)
tree, err := repo.LoadTree(id)
if err != nil {
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) {
tree, err := restic.LoadTree(repo, treeID)
tree, err := repo.LoadTree(treeID)
if err != nil {
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())
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)
job = treeJob{ID: treeID, error: err, Tree: tree}
outCh = out

View File

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

View File

@ -29,7 +29,7 @@ type dir struct {
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())
tree, err := restic.LoadTree(repo, *node.Subtree)
tree, err := repo.LoadTree(*node.Subtree)
if err != nil {
debug.Log("newDir", " error loading tree %v: %v", node.Subtree.Str(), err)
return nil, err
@ -59,7 +59,7 @@ func replaceSpecialNodes(repo *repository.Repository, node *restic.Node) ([]*res
return []*restic.Node{node}, nil
}
tree, err := restic.LoadTree(repo, *node.Subtree)
tree, err := repo.LoadTree(*node.Subtree)
if err != nil {
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) {
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 {
debug.Log("newDirFromSnapshot", " loadTree(%v) failed: %v", snapshot.ID.Str(), err)
return nil, err

View File

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

View File

@ -31,10 +31,11 @@ type Repository interface {
SaveAndEncrypt(BlobType, []byte, *ID) (ID, error)
SaveJSONUnpacked(FileType, interface{}) (ID, error)
LoadJSONPack(BlobType, ID, interface{}) error
LoadJSONUnpacked(FileType, ID, interface{}) error
LoadBlob(ID, BlobType, []byte) ([]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.

View File

@ -589,3 +589,45 @@ func (r *Repository) Delete() error {
func (r *Repository) Close() error {
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 {
tree, err := LoadTree(res.repo, treeID)
tree, err := res.repo.LoadTree(treeID)
if err != nil {
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))
}
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.
func (t Tree) Equals(other *Tree) bool {
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")
}
// Find returns a node with the given name.
func (t Tree) Find(name string) (*Node, error) {
_, node, err := t.binarySearch(name)
return node, err

View File

@ -104,7 +104,7 @@ func TestLoadTree(t *testing.T) {
OK(t, repo.Flush())
// load tree again
tree2, err := restic.LoadTree(repo, id)
tree2, err := repo.LoadTree(id)
OK(t, err)
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
// 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
// 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())
load := func(id restic.ID) (*restic.Tree, error) {
tree := &restic.Tree{}
err := repo.LoadJSONPack(restic.TreeBlob, id, tree)
tree, err := repo.LoadTree(id)
if err != nil {
return nil, err
}

View File

@ -95,9 +95,9 @@ type delayRepo struct {
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)
return d.repo.LoadJSONPack(t, id, dst)
return d.repo.LoadTree(id)
}
var repoFixture = filepath.Join("testdata", "walktree-test-repo.tar.gz")