2
2
mirror of https://github.com/octoleo/restic.git synced 2024-11-30 08:44:02 +00:00

Implement Repack()

This commit is contained in:
Alexander Neumann 2016-08-15 18:10:39 +02:00
parent d5f42201c5
commit 0e6c72ad1d

View File

@ -1,9 +1,12 @@
package repository package repository
import ( import (
"bytes"
"fmt" "fmt"
"io"
"os" "os"
"restic/backend" "restic/backend"
"restic/crypto"
"restic/debug" "restic/debug"
"restic/pack" "restic/pack"
"restic/worker" "restic/worker"
@ -11,38 +14,54 @@ import (
// Repack takes a list of packs together with a list of blobs contained in // Repack takes a list of packs together with a list of blobs contained in
// these packs. Each pack is loaded and the blobs listed in keepBlobs is saved // these packs. Each pack is loaded and the blobs listed in keepBlobs is saved
// into a new pack. Afterwards, the packs are removed. // into a new pack. Afterwards, the packs are removed. This operation requires
func Repack(repo *Repository, packs, keepBlobs backend.IDSet) error { // an exclusive lock on the repo.
func Repack(repo *Repository, packs, keepBlobs backend.IDSet) (err error) {
debug.Log("Repack", "repacking %d packs while keeping %d blobs", len(packs), len(keepBlobs)) debug.Log("Repack", "repacking %d packs while keeping %d blobs", len(packs), len(keepBlobs))
var buf []byte buf := make([]byte, 0, maxPackSize)
for packID := range packs { for packID := range packs {
list, err := repo.ListPack(packID) // load the complete blob
h := backend.Handle{Type: backend.Data, Name: packID.String()}
l, err := repo.Backend().Load(h, buf[:cap(buf)], 0)
if err == io.ErrUnexpectedEOF {
err = nil
buf = buf[:l]
}
if err != nil { if err != nil {
return err return err
} }
debug.Log("Repack", "processing pack %v, blobs: %v", packID.Str(), list) debug.Log("Repack", "pack %v loaded (%d bytes)", packID.Str(), len(buf))
for _, blob := range list { unpck, err := pack.NewUnpacker(repo.Key(), bytes.NewReader(buf))
if !keepBlobs.Has(blob.ID) { if err != nil {
return err
}
debug.Log("Repack", "processing pack %v, blobs: %v", packID.Str(), len(unpck.Entries))
var plaintext []byte
for _, entry := range unpck.Entries {
if !keepBlobs.Has(entry.ID) {
continue continue
} }
buf, err = repo.LoadBlob(blob.Type, blob.ID, buf) ciphertext := buf[entry.Offset : entry.Offset+entry.Length]
if err != nil { plaintext, err = crypto.Decrypt(repo.Key(), plaintext, ciphertext)
return err
}
debug.Log("Repack", " loaded blob %v", blob.ID.Str())
_, err = repo.SaveAndEncrypt(blob.Type, buf, &blob.ID)
if err != nil { if err != nil {
return err return err
} }
debug.Log("Repack", " saved blob %v", blob.ID.Str()) _, err = repo.SaveAndEncrypt(entry.Type, plaintext, &entry.ID)
if err != nil {
return err
}
keepBlobs.Delete(blob.ID) debug.Log("Repack", " saved blob %v", entry.ID.Str())
keepBlobs.Delete(entry.ID)
} }
} }