Merge pull request #1265 from restic/improve-packers

Improve packers, prepare for cache
This commit is contained in:
Alexander Neumann 2017-09-22 16:16:10 +02:00
commit 8f9bf1995b
3 changed files with 45 additions and 35 deletions

View file

@ -38,8 +38,6 @@ type packerManager struct {
} }
const minPackSize = 4 * 1024 * 1024 const minPackSize = 4 * 1024 * 1024
const maxPackSize = 16 * 1024 * 1024
const maxPackers = 200
// newPackerManager returns an new packer manager which writes temporary files // newPackerManager returns an new packer manager which writes temporary files
// to a temporary directory // to a temporary directory
@ -52,25 +50,19 @@ func newPackerManager(be Saver, key *crypto.Key) *packerManager {
// findPacker returns a packer for a new blob of size bytes. Either a new one is // findPacker returns a packer for a new blob of size bytes. Either a new one is
// created or one is returned that already has some blobs. // created or one is returned that already has some blobs.
func (r *packerManager) findPacker(size uint) (packer *Packer, err error) { func (r *packerManager) findPacker() (packer *Packer, err error) {
r.pm.Lock() r.pm.Lock()
defer r.pm.Unlock() defer r.pm.Unlock()
// search for a suitable packer // search for a suitable packer
if len(r.packers) > 0 { if len(r.packers) > 0 {
debug.Log("searching packer for %d bytes\n", size) p := r.packers[0]
for i, p := range r.packers { r.packers = r.packers[1:]
if p.Packer.Size()+size < maxPackSize { return p, nil
debug.Log("found packer %v", p)
// remove from list
r.packers = append(r.packers[:i], r.packers[i+1:]...)
return p, nil
}
}
} }
// no suitable packer found, return new // no suitable packer found, return new
debug.Log("create new pack for %d bytes", size) debug.Log("create new pack")
tmpfile, err := fs.TempFile("", "restic-temp-pack-") tmpfile, err := fs.TempFile("", "restic-temp-pack-")
if err != nil { if err != nil {
return nil, errors.Wrap(err, "fs.TempFile") return nil, errors.Wrap(err, "fs.TempFile")

View file

@ -72,7 +72,7 @@ func fillPacks(t testing.TB, rnd *randReader, be Saver, pm *packerManager, buf [
l := rnd.rand.Intn(1 << 20) l := rnd.rand.Intn(1 << 20)
seed := rnd.rand.Int63() seed := rnd.rand.Int63()
packer, err := pm.findPacker(uint(l)) packer, err := pm.findPacker()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -91,7 +91,7 @@ func fillPacks(t testing.TB, rnd *randReader, be Saver, pm *packerManager, buf [
} }
bytes += l bytes += l
if packer.Size() < minPackSize && pm.countPacker() < maxPackers { if packer.Size() < minPackSize {
pm.insertPacker(packer) pm.insertPacker(packer)
continue continue
} }

View file

@ -24,15 +24,17 @@ type Repository struct {
keyName string keyName string
idx *MasterIndex idx *MasterIndex
*packerManager treePM *packerManager
dataPM *packerManager
} }
// New returns a new repository with backend be. // New returns a new repository with backend be.
func New(be restic.Backend) *Repository { func New(be restic.Backend) *Repository {
repo := &Repository{ repo := &Repository{
be: be, be: be,
idx: NewMasterIndex(), idx: NewMasterIndex(),
packerManager: newPackerManager(be, nil), dataPM: newPackerManager(be, nil),
treePM: newPackerManager(be, nil),
} }
return repo return repo
@ -180,7 +182,18 @@ func (r *Repository) SaveAndEncrypt(ctx context.Context, t restic.BlobType, data
} }
// find suitable packer and add blob // find suitable packer and add blob
packer, err := r.findPacker(uint(len(ciphertext))) var pm *packerManager
switch t {
case restic.TreeBlob:
pm = r.treePM
case restic.DataBlob:
pm = r.dataPM
default:
panic(fmt.Sprintf("invalid type: %v", t))
}
packer, err := pm.findPacker()
if err != nil { if err != nil {
return restic.ID{}, err return restic.ID{}, err
} }
@ -191,11 +204,10 @@ func (r *Repository) SaveAndEncrypt(ctx context.Context, t restic.BlobType, data
return restic.ID{}, err return restic.ID{}, err
} }
// if the pack is not full enough and there are less than maxPackers // if the pack is not full enough, put back to the list
// packers, put back to the list if packer.Size() < minPackSize {
if packer.Size() < minPackSize && r.countPacker() < maxPackers {
debug.Log("pack is not full enough (%d bytes)", packer.Size()) debug.Log("pack is not full enough (%d bytes)", packer.Size())
r.insertPacker(packer) pm.insertPacker(packer)
return *id, nil return *id, nil
} }
@ -239,18 +251,22 @@ func (r *Repository) SaveUnpacked(ctx context.Context, t restic.FileType, p []by
// Flush saves all remaining packs. // Flush saves all remaining packs.
func (r *Repository) Flush() error { func (r *Repository) Flush() error {
r.pm.Lock() for _, pm := range []*packerManager{r.dataPM, r.treePM} {
defer r.pm.Unlock() pm.pm.Lock()
debug.Log("manually flushing %d packs", len(r.packerManager.packers)) debug.Log("manually flushing %d packs", len(pm.packers))
for _, p := range pm.packers {
for _, p := range r.packerManager.packers { err := r.savePacker(p)
err := r.savePacker(p) if err != nil {
if err != nil { pm.pm.Unlock()
return err return err
}
} }
pm.packers = pm.packers[:0]
pm.pm.Unlock()
} }
r.packerManager.packers = r.packerManager.packers[:0]
return nil return nil
} }
@ -372,7 +388,8 @@ func (r *Repository) SearchKey(ctx context.Context, password string, maxKeys int
} }
r.key = key.master r.key = key.master
r.packerManager.key = key.master r.dataPM.key = key.master
r.treePM.key = key.master
r.keyName = key.Name() r.keyName = key.Name()
r.cfg, err = restic.LoadConfig(ctx, r) r.cfg, err = restic.LoadConfig(ctx, r)
return err return err
@ -406,7 +423,8 @@ func (r *Repository) init(ctx context.Context, password string, cfg restic.Confi
} }
r.key = key.master r.key = key.master
r.packerManager.key = key.master r.dataPM.key = key.master
r.treePM.key = key.master
r.keyName = key.Name() r.keyName = key.Name()
r.cfg = cfg r.cfg = cfg
_, err = r.SaveJSONUnpacked(ctx, restic.ConfigFile, cfg) _, err = r.SaveJSONUnpacked(ctx, restic.ConfigFile, cfg)