1
0
mirror of https://github.com/restic/restic.git synced 2024-07-15 10:44:20 +02:00

Merge pull request #998 from restic/fix-820

fuse: Add cache for blob sizes
This commit is contained in:
Alexander Neumann 2017-06-08 20:21:26 +02:00
commit 92c0aa3854
6 changed files with 61 additions and 22 deletions

View File

@ -20,6 +20,10 @@ Important Changes in 0.X.Y
https://github.com/restic/restic/issues/989 https://github.com/restic/restic/issues/989
https://github.com/restic/restic/pull/993 https://github.com/restic/restic/pull/993
* Improved performance for the fuse mount: Listing directories which contain
large files now is significantly faster.
https://github.com/restic/restic/pull/998
Important Changes in 0.6.1 Important Changes in 0.6.1
========================== ==========================

View File

@ -8,7 +8,6 @@ import (
"path" "path"
"restic" "restic"
"strings" "strings"
"sync"
"time" "time"
"restic/backend" "restic/backend"
@ -27,8 +26,6 @@ type s3 struct {
sem *backend.Semaphore sem *backend.Semaphore
bucketname string bucketname string
prefix string prefix string
cacheMutex sync.RWMutex
cacheObjSize map[string]int64
backend.Layout backend.Layout
} }
@ -57,7 +54,6 @@ func Open(cfg Config) (restic.Backend, error) {
sem: sem, sem: sem,
bucketname: cfg.Bucket, bucketname: cfg.Bucket,
prefix: cfg.Prefix, prefix: cfg.Prefix,
cacheObjSize: make(map[string]int64),
} }
client.SetCustomTransport(backend.Transport()) client.SetCustomTransport(backend.Transport())

View File

@ -24,9 +24,11 @@ type dir struct {
inode uint64 inode uint64
node *restic.Node node *restic.Node
ownerIsRoot bool ownerIsRoot bool
blobsize *BlobSizeCache
} }
func newDir(ctx context.Context, repo restic.Repository, node *restic.Node, ownerIsRoot bool) (*dir, error) { func newDir(ctx context.Context, repo restic.Repository, node *restic.Node, ownerIsRoot bool, blobsize *BlobSizeCache) (*dir, error) {
debug.Log("new dir for %v (%v)", node.Name, node.Subtree.Str()) debug.Log("new dir for %v (%v)", node.Name, node.Subtree.Str())
tree, err := repo.LoadTree(ctx, *node.Subtree) tree, err := repo.LoadTree(ctx, *node.Subtree)
if err != nil { if err != nil {
@ -44,6 +46,7 @@ func newDir(ctx context.Context, repo restic.Repository, node *restic.Node, owne
items: items, items: items,
inode: node.Inode, inode: node.Inode,
ownerIsRoot: ownerIsRoot, ownerIsRoot: ownerIsRoot,
blobsize: blobsize,
}, nil }, nil
} }
@ -66,7 +69,7 @@ func replaceSpecialNodes(ctx context.Context, repo restic.Repository, node *rest
return tree.Nodes, nil return tree.Nodes, nil
} }
func newDirFromSnapshot(ctx context.Context, repo restic.Repository, snapshot SnapshotWithId, ownerIsRoot bool) (*dir, error) { func newDirFromSnapshot(ctx context.Context, repo restic.Repository, snapshot SnapshotWithId, ownerIsRoot bool, blobsize *BlobSizeCache) (*dir, error) {
debug.Log("new dir for snapshot %v (%v)", snapshot.ID.Str(), snapshot.Tree.Str()) debug.Log("new dir for snapshot %v (%v)", snapshot.ID.Str(), snapshot.Tree.Str())
tree, err := repo.LoadTree(ctx, *snapshot.Tree) tree, err := repo.LoadTree(ctx, *snapshot.Tree)
if err != nil { if err != nil {
@ -99,6 +102,7 @@ func newDirFromSnapshot(ctx context.Context, repo restic.Repository, snapshot Sn
items: items, items: items,
inode: inodeFromBackendID(snapshot.ID), inode: inodeFromBackendID(snapshot.ID),
ownerIsRoot: ownerIsRoot, ownerIsRoot: ownerIsRoot,
blobsize: blobsize,
}, nil }, nil
} }
@ -167,9 +171,9 @@ func (d *dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
} }
switch node.Type { switch node.Type {
case "dir": case "dir":
return newDir(ctx, d.repo, node, d.ownerIsRoot) return newDir(ctx, d.repo, node, d.ownerIsRoot, d.blobsize)
case "file": case "file":
return newFile(d.repo, node, d.ownerIsRoot) return newFile(d.repo, node, d.ownerIsRoot, d.blobsize)
case "symlink": case "symlink":
return newLink(d.repo, node, d.ownerIsRoot) return newLink(d.repo, node, d.ownerIsRoot)
default: default:

View File

@ -41,15 +41,18 @@ type file struct {
const defaultBlobSize = 128 * 1024 const defaultBlobSize = 128 * 1024
func newFile(repo BlobLoader, node *restic.Node, ownerIsRoot bool) (*file, error) { func newFile(repo BlobLoader, node *restic.Node, ownerIsRoot bool, blobsize *BlobSizeCache) (fusefile *file, err error) {
debug.Log("create new file for %v with %d blobs", node.Name, len(node.Content)) debug.Log("create new file for %v with %d blobs", node.Name, len(node.Content))
var bytes uint64 var bytes uint64
sizes := make([]int, len(node.Content)) sizes := make([]int, len(node.Content))
for i, id := range node.Content { for i, id := range node.Content {
size, err := repo.LookupBlobSize(id, restic.DataBlob) size, ok := blobsize.Lookup(id)
if !ok {
size, err = repo.LookupBlobSize(id, restic.DataBlob)
if err != nil { if err != nil {
return nil, err return nil, err
} }
}
sizes[i] = int(size) sizes[i] = int(size)
bytes += uint64(size) bytes += uint64(size)

View File

@ -108,7 +108,7 @@ func TestFuseFile(t *testing.T) {
Size: filesize, Size: filesize,
Content: content, Content: content,
} }
f, err := newFile(repo, node, false) f, err := newFile(repo, node, false, nil)
OK(t, err) OK(t, err)
attr := fuse.Attr{} attr := fuse.Attr{}

View File

@ -14,10 +14,39 @@ import (
"restic" "restic"
"restic/debug" "restic/debug"
"restic/repository"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
// BlobSizeCache caches the size of blobs in the repo.
type BlobSizeCache struct {
m map[restic.ID]uint
}
// NewBlobSizeCache returns a new blob size cache containing all entries from midx.
func NewBlobSizeCache(midx *repository.MasterIndex) *BlobSizeCache {
m := make(map[restic.ID]uint, 1000)
for _, idx := range midx.All() {
for pb := range idx.Each(nil) {
m[pb.ID] = pb.Length
}
}
return &BlobSizeCache{
m: m,
}
}
// Lookup returns the size of the blob id.
func (c *BlobSizeCache) Lookup(id restic.ID) (size uint, found bool) {
if c == nil {
return 0, false
}
size, found = c.m[id]
return size, found
}
type SnapshotWithId struct { type SnapshotWithId struct {
*restic.Snapshot *restic.Snapshot
restic.ID restic.ID
@ -36,6 +65,8 @@ type SnapshotsDir struct {
tags []string tags []string
host string host string
blobsize *BlobSizeCache
// knownSnapshots maps snapshot timestamp to the snapshot // knownSnapshots maps snapshot timestamp to the snapshot
sync.RWMutex sync.RWMutex
knownSnapshots map[string]SnapshotWithId knownSnapshots map[string]SnapshotWithId
@ -53,6 +84,7 @@ func NewSnapshotsDir(repo restic.Repository, ownerIsRoot bool, paths []string, t
host: host, host: host,
knownSnapshots: make(map[string]SnapshotWithId), knownSnapshots: make(map[string]SnapshotWithId),
processed: restic.NewIDSet(), processed: restic.NewIDSet(),
blobsize: NewBlobSizeCache(repo.Index().(*repository.MasterIndex)),
} }
} }
@ -158,5 +190,5 @@ func (sn *SnapshotsDir) Lookup(ctx context.Context, name string) (fs.Node, error
} }
} }
return newDirFromSnapshot(ctx, sn.repo, snapshot, sn.ownerIsRoot) return newDirFromSnapshot(ctx, sn.repo, snapshot, sn.ownerIsRoot, sn.blobsize)
} }