Merge pull request #1589 from restic/fix-intermediate-index-upload

archiver: Fix intermediate index upload
This commit is contained in:
Alexander Neumann 2018-01-27 12:22:11 +01:00
commit e706f1a8d1
2 changed files with 25 additions and 6 deletions

17
changelog/0.8.2/pull-1589 Normal file
View File

@ -0,0 +1,17 @@
Bugfix: Complete intermediate index upload
After a user posted a comprehensive report of what he observed, we were able to
find a bug and correct it: During backup, restic uploads so-called
"intermediate" index files. When the backup finishes during a transfer of such
an intermediate index, the upload is cancelled, but the backup is finished
without an error. This leads to an inconsistent state, where the snapshot
references data that is contained in the repo, but is not referenced in any
index.
The situation can be resolved by building a new index with `rebuild-index`, but
looks very confusing at first. Since all the data got uploaded to the repo
successfully, there was no risk of data loss, just minor inconvenience for our
users.
https://github.com/restic/restic/pull/1589
https://forum.restic.net/t/error-loading-tree-check-prune-and-forget-gives-error-b2-backend/406

View File

@ -620,7 +620,7 @@ func (j archiveJob) Copy() pipe.Job {
const saveIndexTime = 30 * time.Second const saveIndexTime = 30 * time.Second
// saveIndexes regularly queries the master index for full indexes and saves them. // saveIndexes regularly queries the master index for full indexes and saves them.
func (arch *Archiver) saveIndexes(ctx context.Context, wg *sync.WaitGroup) { func (arch *Archiver) saveIndexes(saveCtx, shutdownCtx context.Context, wg *sync.WaitGroup) {
defer wg.Done() defer wg.Done()
ticker := time.NewTicker(saveIndexTime) ticker := time.NewTicker(saveIndexTime)
@ -628,11 +628,13 @@ func (arch *Archiver) saveIndexes(ctx context.Context, wg *sync.WaitGroup) {
for { for {
select { select {
case <-ctx.Done(): case <-saveCtx.Done():
return
case <-shutdownCtx.Done():
return return
case <-ticker.C: case <-ticker.C:
debug.Log("saving full indexes") debug.Log("saving full indexes")
err := arch.repo.SaveFullIndex(ctx) err := arch.repo.SaveFullIndex(saveCtx)
if err != nil { if err != nil {
debug.Log("save indexes returned an error: %v", err) debug.Log("save indexes returned an error: %v", err)
fmt.Fprintf(os.Stderr, "error saving preliminary index: %v\n", err) fmt.Fprintf(os.Stderr, "error saving preliminary index: %v\n", err)
@ -748,16 +750,16 @@ func (arch *Archiver) Snapshot(ctx context.Context, p *restic.Progress, paths, t
// run index saver // run index saver
var wgIndexSaver sync.WaitGroup var wgIndexSaver sync.WaitGroup
indexCtx, indexCancel := context.WithCancel(ctx) shutdownCtx, indexShutdown := context.WithCancel(ctx)
wgIndexSaver.Add(1) wgIndexSaver.Add(1)
go arch.saveIndexes(indexCtx, &wgIndexSaver) go arch.saveIndexes(ctx, shutdownCtx, &wgIndexSaver)
// wait for all workers to terminate // wait for all workers to terminate
debug.Log("wait for workers") debug.Log("wait for workers")
wg.Wait() wg.Wait()
// stop index saver // stop index saver
indexCancel() indexShutdown()
wgIndexSaver.Wait() wgIndexSaver.Wait()
debug.Log("workers terminated") debug.Log("workers terminated")