LoadBlob: use buffer as scratch space

benchmark               old bytes     new bytes     delta
    BenchmarkLoadBlob-4     1010128       2256          -99.78%
This commit is contained in:
Alexander Neumann 2017-01-13 12:33:06 +01:00
parent 215af5c60a
commit 9a5b9253c4
2 changed files with 12 additions and 19 deletions

View file

@ -81,17 +81,6 @@ func (r *Repository) LoadAndDecrypt(t restic.FileType, id restic.ID) ([]byte, er
func (r *Repository) loadBlob(id restic.ID, t restic.BlobType, plaintextBuf []byte) (int, error) {
debug.Log("load %v with id %v (buf %p, len %d)", t, id.Str(), plaintextBuf, len(plaintextBuf))
// lookup plaintext size of blob
size, err := r.idx.LookupSize(id, t)
if err != nil {
return 0, err
}
// make sure the plaintext buffer is large enough, extend otherwise
if len(plaintextBuf) < int(size) {
return 0, errors.Errorf("buffer is too small: %d < %d", len(plaintextBuf), size)
}
// lookup packs
blobs, err := r.idx.Lookup(id, t)
if err != nil {
@ -109,8 +98,8 @@ func (r *Repository) loadBlob(id restic.ID, t restic.BlobType, plaintextBuf []by
// load blob from pack
h := restic.Handle{Type: restic.DataFile, Name: blob.PackID.String()}
ciphertextBuf := make([]byte, blob.Length)
n, err := r.be.Load(h, ciphertextBuf, int64(blob.Offset))
plaintextBuf = plaintextBuf[:cap(plaintextBuf)]
n, err := r.be.Load(h, plaintextBuf, int64(blob.Offset))
if err != nil {
debug.Log("error loading blob %v: %v", blob, err)
lastError = err
@ -125,7 +114,7 @@ func (r *Repository) loadBlob(id restic.ID, t restic.BlobType, plaintextBuf []by
}
// decrypt
n, err = r.decryptTo(plaintextBuf, ciphertextBuf)
n, err = r.decryptTo(plaintextBuf, plaintextBuf)
if err != nil {
lastError = errors.Errorf("decrypting blob %v failed: %v", id, err)
continue
@ -528,7 +517,9 @@ func (r *Repository) Close() error {
return r.be.Close()
}
// LoadBlob loads a blob of type t from the repository to the buffer.
// LoadBlob loads a blob of type t from the repository to the buffer. buf must
// be large enough to hold the encrypted blob, since it is used as scratch
// space.
func (r *Repository) LoadBlob(t restic.BlobType, id restic.ID, buf []byte) (int, error) {
debug.Log("load blob %v into buf %p", id.Str(), buf)
size, err := r.idx.LookupSize(id, t)
@ -536,8 +527,9 @@ func (r *Repository) LoadBlob(t restic.BlobType, id restic.ID, buf []byte) (int,
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 = buf[:cap(buf)]
if len(buf) < int(size)+crypto.Extension {
return 0, errors.Errorf("buffer is too small for data blob (%d < %d)", len(buf), size+crypto.Extension)
}
n, err := r.loadBlob(id, t, buf)
@ -571,7 +563,7 @@ func (r *Repository) LoadTree(id restic.ID) (*restic.Tree, error) {
}
debug.Log("size is %d, create buffer", size)
buf := make([]byte, size)
buf := make([]byte, size+crypto.Extension)
n, err := r.loadBlob(id, restic.TreeBlob, buf)
if err != nil {

View file

@ -11,6 +11,7 @@ import (
"restic"
"restic/archiver"
"restic/crypto"
"restic/repository"
. "restic/test"
)
@ -152,7 +153,7 @@ func BenchmarkLoadBlob(b *testing.B) {
defer cleanup()
length := 1000000
buf := make([]byte, length)
buf := make([]byte, length, length+crypto.Extension)
_, err := io.ReadFull(rnd, buf)
OK(b, err)