2
2
mirror of https://github.com/octoleo/restic.git synced 2024-11-26 23:06:32 +00:00

Merge pull request #392 from restic/fix-build

Allow saving duplicate blobs in the repacker
This commit is contained in:
Alexander Neumann 2016-01-17 22:02:09 +01:00
commit 4d7e802c44
6 changed files with 49 additions and 45 deletions

View File

@ -136,7 +136,7 @@ func repackBlob(src, dst *repository.Repository, id backend.ID) error {
return errors.New("LoadBlob returned wrong data, len() doesn't match") return errors.New("LoadBlob returned wrong data, len() doesn't match")
} }
_, err = dst.SaveAndEncrypt(blob.Type, buf, &id) _, err = dst.SaveAndEncrypt(blob.Type, buf, &id, true)
if err != nil { if err != nil {
return err return err
} }

View File

@ -133,7 +133,6 @@ func TestLargeEncrypt(t *testing.T) {
func BenchmarkEncryptWriter(b *testing.B) { func BenchmarkEncryptWriter(b *testing.B) {
size := 8 << 20 // 8MiB size := 8 << 20 // 8MiB
rd := RandomReader(23, size)
k := crypto.NewRandomKey() k := crypto.NewRandomKey()
@ -141,7 +140,7 @@ func BenchmarkEncryptWriter(b *testing.B) {
b.SetBytes(int64(size)) b.SetBytes(int64(size))
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
rd.Seek(0, 0) rd := RandomReader(23, size)
wr := crypto.EncryptTo(k, ioutil.Discard) wr := crypto.EncryptTo(k, ioutil.Discard)
n, err := io.Copy(wr, rd) n, err := io.Copy(wr, rd)
OK(b, err) OK(b, err)
@ -195,14 +194,13 @@ func BenchmarkEncryptDecryptReader(b *testing.B) {
k := crypto.NewRandomKey() k := crypto.NewRandomKey()
size := 8 << 20 // 8MiB size := 8 << 20 // 8MiB
rd := RandomReader(23, size)
b.ResetTimer() b.ResetTimer()
b.SetBytes(int64(size)) b.SetBytes(int64(size))
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
rd.Seek(0, 0) rd := RandomReader(23, size)
buf.Reset() buf.Reset()
wr := crypto.EncryptTo(k, buf) wr := crypto.EncryptTo(k, buf)
_, err := io.Copy(wr, rd) _, err := io.Copy(wr, rd)

View File

@ -155,25 +155,32 @@ func (mi *MasterIndex) Current() *Index {
} }
// AddInFlight add the given ID to the list of in-flight IDs. An error is // AddInFlight add the given ID to the list of in-flight IDs. An error is
// returned when the ID is already in the list. // returned when the ID is already in the list. Setting ignoreDuplicates to
func (mi *MasterIndex) AddInFlight(id backend.ID) error { // true only checks the in flight list, otherwise the index itself is also
// tested.
func (mi *MasterIndex) AddInFlight(id backend.ID, ignoreDuplicates bool) error {
// The index + inFlight store must be searched for a matching id in one // The index + inFlight store must be searched for a matching id in one
// atomic operation. This requires locking the inFlight store and the // atomic operation. This requires locking the inFlight store and the
// index together! // index together!
mi.inFlight.Lock() mi.inFlight.Lock()
defer mi.inFlight.Unlock() defer mi.inFlight.Unlock()
if !ignoreDuplicates {
// Note: mi.Has read locks the index again. // Note: mi.Has read locks the index again.
mi.idxMutex.RLock() mi.idxMutex.RLock()
defer mi.idxMutex.RUnlock() defer mi.idxMutex.RUnlock()
debug.Log("MasterIndex.AddInFlight", "adding %v", id)
if mi.inFlight.Has(id) {
return fmt.Errorf("%v is already in flight", id)
} }
debug.Log("MasterIndex.AddInFlight", "adding %v", id.Str())
if mi.inFlight.Has(id) {
return fmt.Errorf("%v is already in flight", id.Str())
}
if !ignoreDuplicates {
if mi.Has(id) { if mi.Has(id) {
return fmt.Errorf("%v is already indexed (fully processed)", id) return fmt.Errorf("%v is already indexed (fully processed)", id)
} }
}
mi.inFlight.Insert(id) mi.inFlight.Insert(id)
return nil return nil
@ -187,7 +194,6 @@ func (mi *MasterIndex) IsInFlight(id backend.ID) bool {
mi.inFlight.RLock() mi.inFlight.RLock()
defer mi.inFlight.RUnlock() defer mi.inFlight.RUnlock()
// Note: mi.Has read locks the index again.
mi.idxMutex.RLock() mi.idxMutex.RLock()
defer mi.idxMutex.RUnlock() defer mi.idxMutex.RUnlock()

View File

@ -219,8 +219,9 @@ func (r *Repository) LookupBlobSize(id backend.ID) (uint, error) {
} }
// SaveAndEncrypt encrypts data and stores it to the backend as type t. If data is small // SaveAndEncrypt encrypts data and stores it to the backend as type t. If data is small
// enough, it will be packed together with other small blobs. // enough, it will be packed together with other small blobs. When
func (r *Repository) SaveAndEncrypt(t pack.BlobType, data []byte, id *backend.ID) (backend.ID, error) { // ignoreDuplicates is true, blobs already in the index will be saved again.
func (r *Repository) SaveAndEncrypt(t pack.BlobType, data []byte, id *backend.ID, ignoreDuplicates bool) (backend.ID, error) {
if id == nil { if id == nil {
// compute plaintext hash // compute plaintext hash
hashedID := backend.Hash(data) hashedID := backend.Hash(data)
@ -241,7 +242,7 @@ func (r *Repository) SaveAndEncrypt(t pack.BlobType, data []byte, id *backend.ID
// add this id to the list of in-flight chunk ids. // add this id to the list of in-flight chunk ids.
debug.Log("Repo.Save", "add %v to list of in-flight IDs", id.Str()) debug.Log("Repo.Save", "add %v to list of in-flight IDs", id.Str())
err = r.idx.AddInFlight(*id) err = r.idx.AddInFlight(*id, ignoreDuplicates)
if err != nil { if err != nil {
debug.Log("Repo.Save", "another goroutine is already working on %v (%v) does already exist", id.Str, t) debug.Log("Repo.Save", "another goroutine is already working on %v (%v) does already exist", id.Str, t)
return *id, nil return *id, nil
@ -284,7 +285,7 @@ func (r *Repository) SaveFrom(t pack.BlobType, id *backend.ID, length uint, rd i
return err return err
} }
_, err = r.SaveAndEncrypt(t, buf, id) _, err = r.SaveAndEncrypt(t, buf, id, false)
if err != nil { if err != nil {
return err return err
} }
@ -308,7 +309,7 @@ func (r *Repository) SaveJSON(t pack.BlobType, item interface{}) (backend.ID, er
} }
buf = wr.Bytes() buf = wr.Bytes()
return r.SaveAndEncrypt(t, buf, nil) return r.SaveAndEncrypt(t, buf, nil, false)
} }
// SaveJSONUnpacked serialises item as JSON and encrypts and saves it in the // SaveJSONUnpacked serialises item as JSON and encrypts and saves it in the

View File

@ -83,7 +83,7 @@ func TestSave(t *testing.T) {
id := backend.Hash(data) id := backend.Hash(data)
// save // save
sid, err := repo.SaveAndEncrypt(pack.Data, data, nil) sid, err := repo.SaveAndEncrypt(pack.Data, data, nil, false)
OK(t, err) OK(t, err)
Equals(t, id, sid) Equals(t, id, sid)
@ -253,7 +253,7 @@ func saveRandomDataBlobs(t testing.TB, repo *repository.Repository, num int, siz
_, err := io.ReadFull(rand.Reader, buf) _, err := io.ReadFull(rand.Reader, buf)
OK(t, err) OK(t, err)
_, err = repo.SaveAndEncrypt(pack.Data, buf, nil) _, err = repo.SaveAndEncrypt(pack.Data, buf, nil, false)
OK(t, err) OK(t, err)
} }
} }

View File

@ -90,7 +90,6 @@ type rndReader struct {
} }
func (r *rndReader) Read(p []byte) (int, error) { func (r *rndReader) Read(p []byte) (int, error) {
fmt.Printf("Read(%v)\n", len(p))
for i := range p { for i := range p {
p[i] = byte(r.src.Uint32()) p[i] = byte(r.src.Uint32())
} }