| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | package repository | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-06-04 11:16:55 +02:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2016-03-06 12:26:25 +01:00
										 |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | 	"sync" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-23 14:21:03 +02:00
										 |  |  | 	"github.com/restic/restic/internal/errors" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/hashing" | 
					
						
							| 
									
										
										
										
											2017-07-24 17:42:25 +02:00
										 |  |  | 	"github.com/restic/restic/internal/restic" | 
					
						
							| 
									
										
										
										
											2017-07-23 14:21:03 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/crypto" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/debug" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/fs" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/pack" | 
					
						
							| 
									
										
										
										
											2020-03-19 11:27:19 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/minio/sha256-simd" | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-05 15:58:39 +01:00
										 |  |  | // Saver implements saving data in a backend. | 
					
						
							|  |  |  | type Saver interface { | 
					
						
							| 
									
										
										
										
											2018-03-03 14:20:54 +01:00
										 |  |  | 	Save(context.Context, restic.Handle, restic.RewindReader) error | 
					
						
							| 
									
										
										
										
											2016-03-05 15:58:39 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-22 17:53:00 +01:00
										 |  |  | // Packer holds a pack.Packer together with a hash writer. | 
					
						
							|  |  |  | type Packer struct { | 
					
						
							|  |  |  | 	*pack.Packer | 
					
						
							|  |  |  | 	hw      *hashing.Writer | 
					
						
							|  |  |  | 	tmpfile *os.File | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | // packerManager keeps a list of open packs and creates new on demand. | 
					
						
							|  |  |  | type packerManager struct { | 
					
						
							| 
									
										
										
										
											2017-01-22 17:53:00 +01:00
										 |  |  | 	be      Saver | 
					
						
							|  |  |  | 	key     *crypto.Key | 
					
						
							|  |  |  | 	pm      sync.Mutex | 
					
						
							|  |  |  | 	packers []*Packer | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-22 21:09:21 +01:00
										 |  |  | const minPackSize = 4 * 1024 * 1024 | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-06 14:20:48 +01:00
										 |  |  | // newPackerManager returns an new packer manager which writes temporary files | 
					
						
							| 
									
										
										
										
											2016-03-06 12:26:25 +01:00
										 |  |  | // to a temporary directory | 
					
						
							| 
									
										
										
										
											2016-03-06 14:20:48 +01:00
										 |  |  | func newPackerManager(be Saver, key *crypto.Key) *packerManager { | 
					
						
							| 
									
										
										
										
											2016-03-06 13:14:06 +01:00
										 |  |  | 	return &packerManager{ | 
					
						
							| 
									
										
										
										
											2016-03-06 12:26:25 +01:00
										 |  |  | 		be:  be, | 
					
						
							|  |  |  | 		key: key, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | // 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. | 
					
						
							| 
									
										
										
										
											2017-07-16 20:16:02 +02:00
										 |  |  | func (r *packerManager) findPacker() (packer *Packer, err error) { | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | 	r.pm.Lock() | 
					
						
							|  |  |  | 	defer r.pm.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// search for a suitable packer | 
					
						
							| 
									
										
										
										
											2017-01-22 17:53:00 +01:00
										 |  |  | 	if len(r.packers) > 0 { | 
					
						
							| 
									
										
										
										
											2017-07-16 20:02:59 +02:00
										 |  |  | 		p := r.packers[0] | 
					
						
							|  |  |  | 		r.packers = r.packers[1:] | 
					
						
							|  |  |  | 		return p, nil | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// no suitable packer found, return new | 
					
						
							| 
									
										
										
										
											2017-07-16 20:16:02 +02:00
										 |  |  | 	debug.Log("create new pack") | 
					
						
							| 
									
										
										
										
											2017-05-10 19:48:22 +02:00
										 |  |  | 	tmpfile, err := fs.TempFile("", "restic-temp-pack-") | 
					
						
							| 
									
										
										
										
											2016-03-06 12:26:25 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-05-10 19:48:22 +02:00
										 |  |  | 		return nil, errors.Wrap(err, "fs.TempFile") | 
					
						
							| 
									
										
										
										
											2016-03-06 12:26:25 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-22 17:53:00 +01:00
										 |  |  | 	hw := hashing.NewWriter(tmpfile, sha256.New()) | 
					
						
							|  |  |  | 	p := pack.NewPacker(r.key, hw) | 
					
						
							|  |  |  | 	packer = &Packer{ | 
					
						
							|  |  |  | 		Packer:  p, | 
					
						
							|  |  |  | 		hw:      hw, | 
					
						
							|  |  |  | 		tmpfile: tmpfile, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return packer, nil | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // insertPacker appends p to s.packs. | 
					
						
							| 
									
										
										
										
											2017-01-22 17:53:00 +01:00
										 |  |  | func (r *packerManager) insertPacker(p *Packer) { | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | 	r.pm.Lock() | 
					
						
							|  |  |  | 	defer r.pm.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-22 17:53:00 +01:00
										 |  |  | 	r.packers = append(r.packers, p) | 
					
						
							|  |  |  | 	debug.Log("%d packers\n", len(r.packers)) | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // savePacker stores p in the backend. | 
					
						
							| 
									
										
										
										
											2017-11-22 06:27:29 -05:00
										 |  |  | func (r *Repository) savePacker(ctx context.Context, t restic.BlobType, p *Packer) error { | 
					
						
							| 
									
										
										
										
											2017-07-16 20:24:37 +02:00
										 |  |  | 	debug.Log("save packer for %v with %d blobs (%d bytes)\n", t, p.Packer.Count(), p.Packer.Size()) | 
					
						
							| 
									
										
										
										
											2017-01-22 17:53:00 +01:00
										 |  |  | 	_, err := p.Packer.Finalize() | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-22 17:53:00 +01:00
										 |  |  | 	id := restic.IDFromHash(p.hw.Sum(nil)) | 
					
						
							| 
									
										
										
										
											2016-09-01 21:19:30 +02:00
										 |  |  | 	h := restic.Handle{Type: restic.DataFile, Name: id.String()} | 
					
						
							| 
									
										
										
										
											2016-01-24 19:30:14 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-03 14:20:54 +01:00
										 |  |  | 	rd, err := restic.NewFileReader(p.tmpfile) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = r.be.Save(ctx, h, rd) | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-09-27 22:35:08 +02:00
										 |  |  | 		debug.Log("Save(%v) error: %v", h, err) | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-27 22:35:08 +02:00
										 |  |  | 	debug.Log("saved as %v", h) | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-16 20:24:37 +02:00
										 |  |  | 	if t == restic.TreeBlob && r.Cache != nil { | 
					
						
							|  |  |  | 		debug.Log("saving tree pack file in cache") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		_, err = p.tmpfile.Seek(0, 0) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return errors.Wrap(err, "Seek") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		err := r.Cache.Save(h, p.tmpfile) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 18:45:15 +01:00
										 |  |  | 	err = p.tmpfile.Close() | 
					
						
							| 
									
										
										
										
											2017-01-22 17:53:00 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return errors.Wrap(err, "close tempfile") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-10 19:48:22 +02:00
										 |  |  | 	err = fs.RemoveIfExists(p.tmpfile.Name()) | 
					
						
							| 
									
										
										
										
											2016-03-06 13:14:06 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2016-08-29 22:16:58 +02:00
										 |  |  | 		return errors.Wrap(err, "Remove") | 
					
						
							| 
									
										
										
										
											2016-03-06 13:14:06 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | 	// update blobs in the index | 
					
						
							| 
									
										
										
										
											2020-06-06 22:20:44 +02:00
										 |  |  | 	debug.Log("  updating blobs %v to pack %v", p.Packer.Blobs(), id) | 
					
						
							|  |  |  | 	r.idx.StorePack(id, p.Packer.Blobs()) | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-06 22:20:44 +02:00
										 |  |  | 	// Save index if full | 
					
						
							| 
									
										
										
										
											2020-06-12 09:24:38 +02:00
										 |  |  | 	if r.noAutoIndexUpdate { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-06 22:20:44 +02:00
										 |  |  | 	return r.SaveFullIndex(ctx) | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // countPacker returns the number of open (unfinished) packers. | 
					
						
							|  |  |  | func (r *packerManager) countPacker() int { | 
					
						
							|  |  |  | 	r.pm.Lock() | 
					
						
							|  |  |  | 	defer r.pm.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-22 17:53:00 +01:00
										 |  |  | 	return len(r.packers) | 
					
						
							| 
									
										
										
										
											2015-11-18 20:20:25 +01:00
										 |  |  | } |